Rust如何定义可持有捕获不可变变量闭包的自定义结构体?
问题解答
你当前定义的call字段用fn(A) -> B函数指针类型是无法实现需求的:Rust中只有不捕获任何环境的闭包才能隐式转换为函数指针,只要闭包捕获了外部变量,就不能再赋值给函数指针类型的字段。
要让结构体支持捕获不可变环境的闭包,你需要使用Rust为闭包提供的Fn trait,有两种常用实现方案:
方案1:泛型静态分发(无运行时开销)
直接将闭包作为泛型参数存入结构体,编译时会做单态化优化,性能最高:
// 基础泛型版本,如果闭包捕获了引用,需要额外补充生命周期标注 struct MyFn<F, A, B> where F: Fn(A) -> B, { call: F, } // 带生命周期标注的版本,适配捕获了引用的闭包,避免悬垂引用问题 struct MyFnWithLifetime<'a, F, A, B> where F: Fn(A) -> B + 'a, { call: F, }
使用方式如下:
let y: &f64 = &3.0; let my_fn = MyFn { call: |x: f64| x + *y }; // 调用测试 assert_eq!((my_fn.call)(1.0), 4.0);
方案2:特征对象动态分发(类型统一)
如果你希望同一个MyFn类型可以承载不同的闭包实例,不需要暴露泛型参数,可以用Box包装dyn Fn特征对象:
// 带生命周期的动态分发版本 struct MyFn<'a, A, B> { call: Box<dyn Fn(A) -> B + 'a>, }
使用方式如下:
let y: &f64 = &3.0; let my_fn = MyFn { call: Box::new(|x: f64| x + *y) }; // 调用测试 assert_eq!((my_fn.call)(1.0), 4.0);
补充说明
Rust闭包有三个核心trait,你可以根据实际场景选择:
FnOnce:仅可调用一次,会拿走捕获变量的所有权FnMut:可多次调用,允许修改捕获的变量Fn:可多次调用,仅会不可变访问捕获的变量,正好匹配你当前需要捕获不可变引用的需求
内容的提问来源于stack exchange,提问作者thoughtpolice
相关产品推荐
相关产品推荐

