3

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 where both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo):

struct Foo;

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

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)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hellow
  • 12,430
  • 7
  • 56
  • 79

2 Answers2

6

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) { ... }
}
trent
  • 25,033
  • 7
  • 51
  • 90
1

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.

hellow
  • 12,430
  • 7
  • 56
  • 79
  • 1
    You are right, it does work in this case because `&'a T` is `Copy` (note that the `&` in `&self.ps[0]` does not do anything and can be deleted). In a more complex scenario, where you had to reborrow with the lifetime of `self`, you would need HRTBs. – trent Nov 03 '18 at 14:39