Rust传递HashSet操作函数指针时borrow checker报错如何解决?
错误原因
- 你在
test方法上定义的泛型生命周期'a是调用方指定的生命周期,你要求传入的_operation必须接收两个生命周期为'a的HashSet引用,返回迭代器的元素生命周期也必须是'a。 - 但你实际传给
_operation的两个参数:&self.data的生命周期和test方法中&mut self的生命周期绑定,&update是test方法内部的局部变量,生命周期仅存在于方法执行过程中,完全不可能满足调用方任意指定的'a约束,因此生命周期检查报错。 - 直接调用
HashSet::intersection能编译的原因是:此时编译器会自动推断出仅适配当前调用上下文的临时生命周期,不需要和外部指定的固定生命周期'a绑定,自然不会有冲突。
正确实现
你可以用两种方案解决问题,按需选择即可:
方案1:简化约束,直接返回HashSet(最易用,无额外性能损耗)
因为你最终都会把迭代器结果收集为HashSet,可以直接把这步逻辑放到闭包内,完全避开生命周期问题:
use std::collections::HashSet; struct Foo { data: HashSet<usize> } impl Foo { fn test<F>(&mut self, _operation: F) where F: Fn(&HashSet<usize>, &HashSet<usize>) -> HashSet<usize>, { let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect(); self.data = _operation(&self.data, &update); } fn new() -> Self { Foo { data: HashSet::new() } } } fn main() { let mut foo: Foo = Foo::new(); // 传交集操作 foo.test(|a, b| a.intersection(b).copied().collect()); // 传并集操作 foo.test(|a, b| a.union(b).copied().collect()); }
方案2:用高阶trait约束(HRTB)适配生命周期
如果你一定要保留返回迭代器的约束,需要用for<'a>语法声明闭包可以适配任意输入的生命周期,而非绑定到外部指定的固定生命周期:
use std::collections::HashSet; struct Foo { data: HashSet<usize> } impl Foo { fn test<F>(&mut self, _operation: F) where // for<'a>表示对任意生命周期'a,该闭包都满足后续约束 F: for<'a> Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> Box<dyn Iterator<Item = &'a usize> + 'a>, { let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect(); self.data = _operation(&self.data, &update).copied().collect(); } fn new() -> Self { Foo { data: HashSet::new() } } } fn main() { let mut foo: Foo = Foo::new(); // 调用时把迭代器包成Box即可 foo.test(|a, b| Box::new(a.intersection(b))); foo.test(|a, b| Box::new(a.union(b))); }
内容的提问来源于stack exchange,提问作者Jesko Hüttenhain
相关产品推荐
相关产品推荐

