0

I tried to implement a trait for applying a function to all fields of struct trough an enum Variant, which should hopefully be always inlined at compilation. Sadly I am not able to figure out the lifetimes at all. The following code returns:

pub enum Variant<'a> { Str(&'a str), Int(usize) }

impl<'a> From<&'a str> for Variant<'a> {
    fn from(value: &'a str) -> Self {
        Variant::Str(value)
    }
}

pub struct Foo<T> { foo: T }

pub trait Foreach {
    fn foreach(&self, fun: impl FnMut(&Variant));
}


impl<'a,T:'a> Foreach for Foo<T> where &'a T: Into<Variant<'a>>{
    fn foreach(&'a self, fun: impl FnMut(&Variant<'a>)) {
        fun("Foo: ".into());
        fun(&(&self.foo).into()); // The variant should never escape this scope. The function should consume it immediately.
    }
}

Following error:

error[E0308]: method not compatible with trait
  --> src/lib.rs:17:5
   |
17 |     fn foreach(&'a self, fun: impl FnMut(&Variant<'a>)) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected fn pointer `fn(&Foo<T>, _)`
              found fn pointer `fn(&'a Foo<T>, _)`
note: the anonymous lifetime #1 defined on the method body at 17:5...
  --> src/lib.rs:17:5
   |
17 | /     fn foreach(&'a self, fun: impl FnMut(&Variant<'a>)) {
18 | |         fun("Foo: ".into());
19 | |         fun(&(&self.foo).into()); // The variant should never escape this scope. The function should consume it immediately.
20 | |     }
   | |_____^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 16:6
  --> src/lib.rs:16:6
   |
16 | impl<'a,T:'a> Foreach for Foo<T> where &'a T: Into<Variant<'a>>{
   |      ^^

error[E0277]: the trait bound `&Variant<'_>: std::convert::From<&str>` is not satisfied
  --> src/lib.rs:18:13
   |
18 |         fun("Foo: ".into());
   |             ^^^^^^^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `&Variant<'_>`
   |
   = help: the following implementations were found:
             <Variant<'a> as std::convert::From<&'a str>>
   = note: `std::convert::From<&str>` is implemented for `&mut Variant<'_>`, but not for `&Variant<'_>`
   = note: required because of the requirements on the impl of `std::convert::Into<&Variant<'_>>` for `&str`

Ford O.
  • 1,394
  • 8
  • 25
  • 2
    I am inclined to link to the higher-rank trait bounds doc after looking at the question for 10 seconds. https://doc.rust-lang.org/nomicon/hrtb.html – idursun Feb 28 '20 at 09:25
  • @idursun Thank you very much. Would you like to officially answer it? – Ford O. Feb 28 '20 at 10:00
  • Does this answer your question? [How to define lifetimes on a Fn trait bound returning references?](https://stackoverflow.com/questions/53566761/how-to-define-lifetimes-on-a-fn-trait-bound-returning-references) – trent Feb 28 '20 at 11:20
  • Other questions that have to do with HRTBs: [How do I write the lifetimes for references in a type constraint when one of them is a local reference?](https://stackoverflow.com/q/44343166/3650362), [How does for<> syntax differ from a regular lifetime bound?](https://stackoverflow.com/q/35592750/3650362), and [Lifetime issues with a closure argument in Rust](https://stackoverflow.com/q/51969236/3650362). It also comes up a lot when dealing with operator overloading, e.g. [How to write a trait bound for adding two references of a generic type?](https://stackoverflow.com/q/34630695/3650362) – trent Feb 28 '20 at 11:34
  • @FordO. posted an answer. – idursun Feb 28 '20 at 11:50

1 Answers1

1

I think you can solve this by using Higher-rank trait bounds which is documented here

From the document:

for<'a> can be read as "for all choices of 'a", and basically produces an infinite list of trait bounds that F must satisfy.

idursun
  • 6,261
  • 1
  • 37
  • 51