Rust中如何实现兼容Fn(&T)与Fn(&mut T)的泛化函数参数?
Rust中如何实现兼容Fn(&T)与Fn(&mut T)的泛化函数参数?
嘿,这个问题我之前也琢磨过,咱们一步步来解决它~
首先先看你给出的原始代码,这个版本的apply_fn只能接受需要&mut u32类型参数的闭包:
fn apply_fn<'a, F>(f: F) where F: Fn(&mut u32), { let mut i = 1; f(&mut i); }
要让它同时兼容接受&u32的闭包,核心思路是利用Rust里的引用转换规则——&mut u32可以隐式转换成&u32,我们可以通过泛型参数来抽象这个兼容的类型。
这里有个简洁的实现方案:
fn apply_fn<F, T>(f: F) where T: ?Sized, &'_ mut u32: Into<T>, F: FnOnce(T), { let mut i = 1; f((&mut i).into()); }
为什么这样可行?
- 我们引入了泛型参数
T,用来表示闭包接受的参数类型 &'_ mut u32: Into<T>这个约束保证了&mut u32可以转换成T:- 当
T是&mut u32时,Into直接返回自身,完全匹配原始逻辑 - 当
T是&u32时,Rust会自动把&mut u32转换成&u32,满足闭包的参数要求
- 当
- 用
FnOnce是因为我们只调用一次闭包,如果你的场景需要多次调用闭包,把它换成Fn就可以了
测试一下两种场景
现在这个函数既能处理可变引用的闭包,也能处理不可变的:
// 测试不可变引用闭包 apply_fn(|x: &u32| println!("拿到不可变值:{}", x)); // 测试可变引用闭包 apply_fn(|x: &mut u32| { *x += 5; println!("修改后的值:{}", x); });
运行这段代码,两种闭包都能正常工作,完全符合你的需求~
备注:内容来源于stack exchange,提问作者tolvanea
相关产品推荐
相关产品推荐

