I hit a case where I need to apply HRTB to multiple generics. I can write the code I want without generics, but I can't figure out how to make it generic.
(Thanks in advance if you decide to read through this whole thing! )
Let me take you on a journey. First, let's look at some working code that does everything I need (but without generics):
fn print_func_result<F>(func: F)
where
for<'a> F: FnOnce(&'a str) -> &'a str,
{
let local_string = String::from("test");
let result = func(&local_string);
println!("{:?}", result);
}
fn accept_me(s: &str) -> &str { s }
fn reject_me(s: &'static str) -> &'static str { s }
fn main() {
print_func_result(|x| accept_me(x));
print_func_result(|x| reject_me(x));
}
The local_string
var is owned by print_func_result
, so Rust will reject reject_me(x)
because the borrow would escape its lifetime. This is good. So far all is well in the world.
Now, let's try to make print_func_result
generic:
fn print_func_result<D, F>(func: F)
where
D: Debug,
for<'a> F: FnOnce(&'a str) -> D,
{}
This will not compile, because (I believe) the compiler uses a default 'static
bound for D
. The correct bound for D
is actually D: Debug + 'a
, but you can't write that type because the name 'a
is not in scope outside the HRTB.
Here are a few of my failed attempts:
fn print_func_result<D, F>(func: F)
where
D: Debug,
for<'a> F: FnOnce(&'a str) -> (D + 'a),
{}
fn print_func_result<D, F>(func: F)
where
for<'a> (
D: Debug + 'a,
F: FnOnce(&'a str) -> D + 'a,
)
{}
And here's a playground link if you'd like to share in my suffering.
I'm sure there's some magic incantation that will make this work. Can anyone enlighten me?