I have a generic function that takes a closure as argument builder: impl for<'a> FnOnce(&'a String) -> Orange<'a>, and I have a impl<'a> From<&'a String> for Orange<'a> impl. I assumed I could have passed the Orange::from function as builder. But it complains with an error I don't really understand:
The problem is that the generic lifetime is declared "on" the Orange type rather than "on" the function itself. That is, there is an Orange<'lifetime1>::from method and an Orange<'lifetime2>::from method, and these are two different non-generic methods defined on different types that differ only by a lifetime. What you wanted is a single function that is generic.
There's no way to use From with this particular definition (impl for<'a> FnOnce(&'a String) -> Orange<'a>). From::from will always be a function with no lifetime parameters, because that's what it is in the trait definition
pub trait From<T> {
pub fn from(T) -> Self;
}
If you use a different trait, it could be possible - for instance, this could work:
It'd work because the into_orange function is generic (and thus matches the FnOnce definition), unlike from.
I think the limitation here is that the compiler has no way to form From::<Orange<'x>>::from into a function generic over <'x>. It theoretically could - I think modifying the compiler to do this could be possible? But right now, the <'x> is a parameter of the trait, and thus needs to be specified in order to even access from. Orange::from doesn't exist as a function to pass in to find_orange without the concrete definition of Orange, which includes a lifetime (and thus the resulting function is not generic over a lifetime, as it's already been decided).
Practically, find_orange(|o| o.into()) should be usable. But I understand that that's not as really nice and pure.
FWIW, this is the question of early-bound vs. late-bound lifetimes: when the generic lifetime parameter infects a function call βand is unbounded!1β, then that function will have a higher-order / universal lifetime signature involving it. But when the lifetime parameter comes from an outer level, such as a generic trait (your case) or a generic type, then the lifetime parameter is not higher-order, but fixed (although it can be inferred to take any necessary lifetime).
1 If the lifetime parameter is bounded, then the function loses its higher-order power over that lifetime parameter, as showcased by the following snippet:
fn example<'lt> (_: &'lt mut ())
where /* trivial bound that does nothing but disabling higher-order-ness */
'lt : 'lt, /* If you comment this out, it compiles */
{}
fn main ()
{
let f = example;
f(&mut ()); // Error, temporary value dropped while borrowed.
f(&mut ());
}