简体   繁体   中英

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)

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)
  • 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
  • The items returned by your iterator are actually references, so you probably want to bind I to 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.

I also needed to use ?Sized as a bound for most type parameters. 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 )

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());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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