pub fn vec2_to_func<K, V>(
vec2: Vec<(K, Vec<V>)>)
-> impl Fn(&K) -> &HashSet<V>
where
K: Eq + Hash,
V: Eq + Hash
{
let mut hm = HashMap::new();
for (k,v) in vec2.into_iter() {
hm.insert(k, HashSet::from_iter(v.into_iter()));
}
let bhm = Box::new(hm);
let g = move |k: &K| -> &HashSet<V> {
bhm.get(k).unwrap()
};
g
}
#[test]
fn test_zutil_dag_vec2_to_func()
{
let g = vec![
(1, vec![2, 3, 4]),
(2, vec![3, 4, 1]),
(3, vec![4, 1, 2]),
(4, vec![]), ];
let f = vec2_to_func(g);
assert_eq!(f(&1), &HashSet::from_iter(vec![2, 3, 4].iter().cloned()));
assert_eq!(f(&2), &HashSet::from_iter(vec![1, 3, 4].iter().cloned()));
assert_eq!(f(&3), &HashSet::from_iter(vec![1, 2, 4].iter().cloned()));
assert_eq!(f(&4), &HashSet::from_iter(vec![].iter().cloned()));
}
I get error:
error[E0271]: type mismatch resolving `for<'r> <[closure@crates/z_zutil/src/dag/vec2_to_func.rs:21:13: 23:6 bhm:_] as std::ops::FnOnce<(&'r K,)>>::Output == &'r std::collections::HashSet<V>`
--> crates/z_zutil/src/dag/vec2_to_func.rs:8:8
|
8 | -> impl Fn(&K) -> &HashSet<V>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
|
= note: the return type of a function must have a statically known size
You're trying to return a reference to a HashSet borrowed from a closure's environment. Unfortunately, the signature:
impl Fn(&K) -> &HashSet<V>
allows the returned value to borrow only from the key argument, but not from the environment. None of three current closure types allows to return a borrow from environment.
As a workaround, you can:
Return a custom struct,
Return an impl of a custom trait,
Return impl Fn(&K) -> Rc<HashSet<V>>. There is some overhead associated with Rc, but compared to the cost of search operation on the hashmap, this overhead shouldn't be noticable.
The note in the error message is really confusing. You should consider filing a bug.
@krdin : The restriction of "can not ref / borrow from Environment" seems very restrictive. Does that mean the following is also 'impossible' to solve as-is ?
It's restrictive for the closure, but it makes life easier for the caller. For example, caller can do:
let x = closure(key1);
// store the x somewhere
// closure goes out of scope
If the return value was allowed to borrow from environment, the caller would need to keep the closure alive to store x. This would be a huge limitation.
Yup, that's basically it.
However, you could add a Clone or Copy bound on T and just return a copy of T by value (by changing return type to -> T). If you really need to borrow a borrow from env from some reason, then you cannot use closures, however, you can freely create a closure-like trait or struct that will allow such behaviour.