Home > Net >  Cannot construct from a reference in a generic function (value does not live long enough)
Cannot construct from a reference in a generic function (value does not live long enough)

Time:05-03

I have a method that takes some parameters, creates (decrypts) an intermediate value from them and tries to construct a type instance from that intermediate value. This works fine as long as the type is fixed. If I want to support multiple types via generics I run into trouble. Here is minified code:

impl Factory
{
    pub fn get<'a, T>(&'a self, value: &'a str) -> T
        where T: From<&'a str>
    {
        let value_parsed = value.chars().rev().collect::<String>();
        return T::from(&value_parsed);
    }
}

You can run the full code here. Compiling produces the following error:

31 |     pub fn get<'a, T>(&'a self, value: &'a str) -> T
   |                -- lifetime `'a` defined here
...
35 |         return T::from(&value_parsed);
   |                --------^^^^^^^^^^^^^-
   |                |       |
   |                |       borrowed value does not live long enough
   |                argument requires that `value_parsed` is borrowed for `'a`
36 |     }
   |     - `value_parsed` dropped here while still borrowed

As I said, using Item in the method signature rather than a generic type gets rid of this error. Not passing a reference to T::from() but rather moving the temporary value is also an option but that makes little sense given that value_parsed isn’t actually being consumed here, it gets awkward and inconsistent with the rest of my codebase.

Any way I can make sure value_parsed lives long enough? Or is there some other solution short of not using references here?

CodePudding user response:

You would use a higher-rank trait bound to indicate that the type T can be made from a value with any lifetime, as opposed to a specific lifetime when used as generics on the function:

pub fn get<T>(&self, value: &str) -> T
    where T: for<'a> From<&'a str>
          // ^^^^^^^

What you had before was indicating that T could be built from a reference with the lifetime based on self and value, however, since value_parsed is a local variable, a reference to it cannot satisfy that lifetime constraint.

CodePudding user response:

Turns out using my own trait works here, one that doesn’t require me to specify a reference to the type in the signature – and consequently doesn’t require associating a lifetime with the trait:

trait Get<T>
{
    fn get(value: &T) -> Self;
}

Using this trait the method can compile:

pub fn get<'a, T>(&'a self, value: &'a str) -> T
    where T: Get<String>
{
    let value_parsed = value.chars().rev().collect::<String>();
    return T::get(&value_parsed);
}

I’m not sure whether this is the best solution, but this solution works.

  • Related