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.