简体   繁体   English

为什么我的Trait实现不匹配?

[英]Why does my Trait implementation not match?

How can I make this code compile ? 如何使此代码编译?

trait Pair<'a, A, B> {
    fn first_ref(&'a self) -> &'a A;
    fn second_ref(&'a self) -> &'a B;
};

struct PairOwned<A, B> {
    first: A,
    second: B,
}

// Only implemented for the cases we are interested in ...
impl<'a, A, B> Pair<'a, A, B> for &'a PairOwned<&'a A,&'a B> {
    fn first_ref(&'a self) -> &'a A {
        self.first
    }
    fn second_ref(&'a self) -> &'a B {
        self.second
    }
}

impl<'a, A, B> Pair<'a, A, B> for &'a(&'a A, &'a B) {
    fn first_ref(&'a self) -> &'a A {
        self.0
    }
    fn second_ref(&'a self) -> &'a B {
        self.1
    }
}

fn pair_transformer<'a, I, T>(pairs: I) -> String
    where   T: Pair<'a, &'a Str, &'a Str> + 'a,
            I: Iterator<Item=T> {
    let mut s = String::new();
    for pair in pairs {
        s = s
            + pair.first_ref().as_slice()
            + pair.second_ref().as_slice();
    }
    s
}

pair_transformer([PairOwned { first: "a", second: "b" }].iter());
pair_transformer([("a", "b")].iter());

The compiler says: 编译器说:

tests/lang.rs:902:5: 902:21 error: the trait `pair_trait_for_iteration::Pair<'_, &core::str::Str, &core::str::Str>` is not implemented for the type `&pair_trait_for_iteration::PairOwned<&str, &str>` [E0277]
 tests/lang.rs:902     pair_transformer([PairOwned { first: "a", second: "b" }].iter());
                      ^~~~~~~~~~~~~~~~
tests/lang.rs:903:5: 903:21 error: the trait `pair_trait_for_iteration::Pair<'_, &core::str::Str, &core::str::Str>` is not implemented for the type `&(&str, &str)` [E0277]
tests/lang.rs:903     pair_transformer([("a", "b")].iter());

Notes 笔记

I have the feeling it is somehow related to the various ways to specify what a trait should be implemented for, something I have not fully understood yet. 我觉得这与指定应针对某个特性实施的各种方式有某种联系,而我对此尚未完全理解。

// As stated in the answer at 
// http://stackoverflow.com/questions/28283641/what-is-the-preferred-way-to-implement-the-add-trait-efficiently-for-vector-type
impl Add<YourType> for YourType { ... }
impl<'r> Add<YourType> for &'r YourType { ... }
impl<'a> Add<&'a YourType> for YourType { ... }
impl<'r, 'a> Add<&'a YourType> for &'r YourType { ... }

Using rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-19) rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-19)使用rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-19)

There are a couple of mistakes in your code: 您的代码中有几个错误:

  • You probably want to implement your trait directly for your type, as the methods defined by the trait take the trait by reference (which is not the case of the Add trait in the other post you linked) 您可能想直接为您的类型实现特征,因为特征定义的方法通过引用来获取特征(在链接的其他帖子中不是“ Add特征”的情况)
  • Your use of OwnedPair { first: "a", second: "b"} isn't actually owned: your type will be OwnedPair<&'static str, &'static str> so I included examples with String (which are owned) as I assume that is what you wanted 您实际上并未拥有对OwnedPair { first: "a", second: "b"}使用权OwnedPair { first: "a", second: "b"} :您的类型将为OwnedPair<&'static str, &'static str>因此我在String包含了示例(已拥有)我以为那就是你想要的
  • The items returned by your iterator are actually references, so you probably want to bind I to Iterator<Item=&'a T> 迭代器返回的项实际上是引用,因此您可能希望将I绑定到Iterator<Item=&'a T>

As I tried to be as generic as possible (and for the example to compile with both OwnedPair<&str,&str> and OwnedPair<String,String> ) I used the trait std::borrow::Borrow, which basically means that it is possible to borrow a reference to the type T from the type by which this trait is implemented. 当我尝试尽可能通用时(例如,使用OwnedPair<&str,&str>OwnedPair<String,String>进行编译的示例),我使用了特性std :: OwnedPair<String,String> :: Borrow,这基本上意味着它是可以从实现此特征的类型中借用对类型T的引用。

I also needed to use ?Sized as a bound for most type parameters. 我还需要使用?Sized作为大多数类型参数的绑定。 This allows to use types which size is not known at compile time, and will be used behind a "fat pointer". 这允许使用大小在编译时未知的类型,并将在“胖指针”后面使用。 More information in this blog post (a little bit old) 此博客文章中的更多信息(有点旧)

Here is the full corrected code (runnable in playpen ) 这是完整的更正代码(可在playpen中运行)

use std::borrow::Borrow;

trait Pair<'a, A: ?Sized, B: ?Sized> {
    fn first_ref(&'a self) -> &'a A;
    fn second_ref(&'a self) -> &'a B;
}

struct PairOwned<A, B> {
    first: A,
    second: B,
}

// Only implemented for the cases we are interested in ...
impl<'a, ARef: ?Sized, BRef: ?Sized, A: Borrow<ARef>, B: Borrow<BRef>> Pair<'a, ARef, BRef> for PairOwned<A,B> {
    fn first_ref(&'a self) -> &'a ARef {
        self.first.borrow()
    }
    fn second_ref(&'a self) -> &'a BRef {
        self.second.borrow()
    }
}

// It should also be possible to be more generic here with Borrow
// But I wanted to leave your original implementation
impl<'a, A: ?Sized, B: ?Sized> Pair<'a, A, B> for (&'a A, &'a B) {
    fn first_ref(&'a self) -> &'a A {
        self.0
    }
    fn second_ref(&'a self) -> &'a B {
        self.1
    }
}

fn pair_transformer<'a, I, T>(pairs: I) -> String
    where   T: Pair<'a, str, str> + 'a,
            I: Iterator<Item=&'a T> {
    let mut s = String::new();
    for pair in pairs {
        s = s
            + pair.first_ref().as_slice()
            + pair.second_ref().as_slice();
    }
    s
}

fn main() {
    pair_transformer([PairOwned { first: "a".to_string(), second: "b".to_string() }].iter());
    pair_transformer([PairOwned { first: "a".to_string(), second: "b" }].iter()); // It is even possible to mix String and &str
    pair_transformer([PairOwned { first: "a", second: "b" }].iter());
    pair_transformer([("a", "b")].iter());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM