I have a "view" data structure in Rust that contains a reference to another data structure, and I want to automate testing of the getter methods that I implemented on the view data structure. Here's a MRE with a single getter:
/// View data structure.
struct View<'a> {
value: &'a u32,
}
impl<'a> View<'a> {
/// Getter method.
pub fn value(&self) -> u32 {
*self.value
}
}
/// Attempt to automate unit testing of the getter: create an underlying value,
/// then create a `View`, then apply the getter method to the `View` and ensure
/// we get the expected value out.
fn check_getter(getter: fn(&View) -> u32) {
let value: u32 = 7;
let view = View { value: &value };
assert!(getter(&view) == 7);
}
check_getter(View::value);
This fails to compile, with the following error:
mismatched types
expected fn pointer `for<'r, 's> fn(&'r tests::test_adcs::View<'s>) -> _`
found fn pointer `for<'r> fn(&'r tests::test_adcs::View<'_>) -> _`
I think I need to use HRTBs, and have tried various permutations, but haven't been able to get anything to compile.
TL;DR: Use a closure (you can use macros if you prefer):
You fell into the trap of early-bound vs. late-bound lifetimes.
View::valuedoes not have the signaturefor<'a> fn <View<'a>>::value(). Rather, it has the signaturefn <View<'some_concrete_lifetime>>::value(). That is,'ais not any lifetime, but some inferred lifetime. Therefore HRTB doesn't work - only one lifetime matches the given function. You can read more about early-bound and late-bound lifetimes in this recent answer I wrote, but the crux of the issue is that because the lifetime'aappears on theimpl, not the function itself, it becomes early-bound and has only one concrete lifetime for each instance of the function instead of being late-bound and allowed to use with any lifetime.The fix is just to wrap it with a closure, making it late-bound.