luke
luke

Reputation: 1104

Sorting out different lifetimes on Self and a method

I posted a similar question (Rust lifetime error expected concrete lifetime but found bound lifetime) last night, but still can't figure out how to apply it to this case now. Once again, a simplified example bellow:

struct Ref;

struct Container<'a> {
  r : &'a Ref
}

struct ContainerB<'a> {
  c : Container<'a>
}

trait ToC {
  fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> Self;
}

impl<'b> ToC for ContainerB<'b> {
  fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
    ContainerB{c:c}
  }
}

With the error message:

test.rs:16:3: 18:4 error: method `from_c` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a
test.rs:16   fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
test.rs:17     ContainerB{c:c}
test.rs:18   }
test.rs:16:67: 18:4 note: expected concrete lifetime is the lifetime 'b as defined on the block at 16:66
test.rs:16   fn from_c<'a>(r : &'a Ref, c : Container<'a>) -> ContainerB<'a> {
test.rs:17     ContainerB{c:c}
test.rs:18   }
error: aborting due to previous error

What I think needs to happen is I need some way to equate / sub-type lifetime 'a, and lifetime 'b. Unlike the previous example there is no &self to use. I am guessing I can do this by adding a lifetime type argument to my trait(trait ToC<'a> ...), but I would prefer not to do this as it adds extra <'a> everywhere I want to use the trait as a type bound.

If anybody is curious(AKA can ignore this) where this might actually come up, I am using it in a library to convert between rust and python types. The trait is here. Everything works fine, but I am trying to implement a wrapper around the PyObject type (such as a numpy ndarray) and be able to convert it to and from a PyObject with this.

Thanks again!

Upvotes: 0

Views: 341

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90902

This boils down to much the same problem as in your previous question.

Self refers to the type you are implementing the trait for. In this case it is ContainerB<'b>, and so the whole thing about its not being the same applies; this time this time there is nothing to tie 'b and 'a together, either; the lifetimes are and must be assumed by the compiler to be potentially disjoint. (This is as distinct to the &'a ContainerB<'b> which guaranteed 'b ≥ 'a.)

Once you are using a lifetime defined on the method, tying that in with a lifetime on Self is not possible. The solution that is probably best is to shift the lifetime parameter from the method onto the trait:

trait ToC<'a> {
    fn from_c(r: &'a Ref, c: Container<'a>) -> Self;
}

impl<'a> ToC<'a> for ContainerB<'a> {
    fn from_c(r: &'a Ref, c: Container<'a>) -> ContainerB<'a> {
        ContainerB { c: c }
    }
}

Upvotes: 1

Related Questions