Wrong trait choosen based on type parameter

2019-07-04 06:41发布

问题:

(I can't come up with a good title, feel free to correct it).

I have a binary trait resolve.

pub trait Resolve<RHS = Self> {
    type Output;
    fn resolve(self, rhs: RHS) -> Self::Output;
}

I implemented the trait for something trivial like struct Foo.

struct Foo;

impl <'a, 'b> Resolve<&'b Foo> for &'a Foo {
    type Output = Foo;
    fn resolve(self, rhs: &'b Foo) -> Self::Output {
        unimplemented!()
    }
}

As you can see, both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo).

If I now write

fn main() {
    let a: &Foo = &Foo;
    let b = Foo;
    a.resolve(&b);
}

it will compile just fine, but if I try to implement it on my struct Signal, it will not work.

pub struct Signal<'a, T> {
    ps: Vec<&'a T>,
}

impl<'a, T: Resolve<&'a T, Output = T> + 'a> Signal<'a, T> {
    pub fn foo(&mut self) {
        let a: &T = &self.ps[0];
        let b = &self.ps[1];
        a.resolve(b);
    }
}
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:25:9
   |
25 |         a.resolve(b);
   |         ^ cannot move out of borrowed content

How do I get this example working? (playground)

回答1:

The trait bound on foo only says that T implements Resolve, but you try to call .resolve() on a value of type &T.

To say, instead, that references to T must implement Resolve, you need a higher-ranked trait bound:

impl<'a, T> Signal<'a, T>
where
    for<'b> &'b T: Resolve<&'a T, Output = T>,
{
    pub fn foo(&mut self) { ... }
}


回答2:

After thinking about this I came up with a simpler solution that does not rely on HRTB.

impl<'a, T> Signal<'a, T>
where
    &'a T: Resolve<&'a T, Output = T> + 'a,
{
    pub fn foo(&mut self) {
        let a: &T = &self.ps[0];
        let b = &self.ps[1];
        a.resolve(b);
    }
}

This does the same, namely describe, that &T implements Resolve, but without the need of HRTB.
You have to use the where clause for this, but apart from that this is a nice and easy solution.



标签: rust