'Cannot construct from a reference in a generic function (value does not live long enough)
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?
Solution 1:[1]
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.
Solution 2:[2]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | kmdreko |
| Solution 2 | Wladimir Palant |
