Rust中向接收Option<impl Fn(i64)->i64>的函数传None的正确方法
问题:如何正确调用接收
Option<impl Fn(i64)->i64>的函数并传递None? 定义了如下Rust代码,尝试调用apply(None)时编译失败,使用None::<dyn Fn(i64)->i64>也无法通过编译:
fn main(){ let a = apply(Some(|i| i + 1)); let b = apply(None); let b2 = apply(None::<dyn Fn(i64)->i64>); println!("a: {0}; b: {1}", a, b) } fn apply(f: Option<impl Fn(i64)->i64>) -> i64 { let i = 0_i64; match f { Some(f) => f(i), None => i, } }
编译错误信息
调用apply(None)时的错误:
Compiling playground v0.0.1 (/playground) error[E0282]: 需要类型标注 --> src/main.rs:4:16 | 4 | let b = apply(None); | ^^^^ 无法推断枚举`Option`上声明的类型参数`T`的类型 | 帮助: 考虑指定泛型参数 | 4 | let b = apply(None::<T>); | +++++ error[E0283]: 需要类型标注 --> src/main.rs:4:16 | 4 | let b = apply(None); | ----- ^^^^ 无法推断枚举`Option`上声明的类型参数`T`的类型 | | | 此调用引入的约束所要求 | = 注意: 在以下 crate 中找到多个满足`_: Fn<(i64,)>`的`impl`:`alloc`, `core`: - impl<A, F> Fn<A> for &F where A: Tuple, F: Fn<A>, F: ?Sized; - impl<Args, F, A> Fn<Args> for Box<F, A> where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized; 注意: `apply`中的约束所要求 --> src/main.rs:10:25 | 10 | fn apply(f: Option<impl Fn(i64)->i64>) -> i64 { | ^^^^^^^^^^^^^^ 此`apply`中的约束所要求 帮助: 考虑指定泛型参数 | 4 | let b = apply(None::<T>); | +++++ Some errors have detailed explanations: E0282, E0283. For more information about an error, try `rustc --explain E0282`.
调用apply(None::<dyn Fn(i64)->i64>)时的错误:
Compiling playground v0.0.1 (/playground) error[E0277]: 无法在编译时确定类型`dyn Fn(i64)->i64`的值的大小 --> src/main.rs:5:20 | 5 | let b2 = apply(None::<dyn Fn(i64)->i64>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 编译时无法确定大小 | = 帮助: trait `Sized`未为`dyn Fn(i64)->i64`实现 注意: `None`中的约束所要求 --> /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/option.rs:567:5 For more information about this error, try `rustc --explain E0277`. error: could not compile `playground` (bin "playground") due to previous error
原因分析
apply函数的Option<impl Fn(i64)->i64>参数本质是隐式泛型参数,编译器需要明确Option内部的具体类型,但None本身不携带类型信息,导致无法推断。dyn Fn(i64)->i64是动态大小类型(DST),而Option<T>默认要求T实现Sizedtrait,因此直接使用None::<dyn Fn(...)>会触发大小不固定的错误。
解决方案
方案1:标注None为函数指针类型
函数指针fn(i64)->i64是大小固定的类型,且满足Fn(i64)->i64约束:
fn main(){ let a = apply(Some(|i| i + 1)); let b = apply(None::<fn(i64)->i64>); // 标注为函数指针类型 println!("a: {0}; b: {1}", a, b) } fn apply(f: Option<impl Fn(i64)->i64>) -> i64 { let i = 0_i64; match f { Some(f) => f(i), None => i, } }
方案2:修改函数参数为Option<Box<dyn Fn(i64)->i64>>
使用Box包裹动态trait对象,Box<dyn Fn(...)>是大小固定的指针类型,编译器可自动推断None的类型:
fn main(){ let a = apply(Some(Box::new(|i| i + 1))); let b = apply(None); // 无需额外标注,编译器自动推断类型 println!("a: {0}; b: {1}", a, b) } fn apply(f: Option<Box<dyn Fn(i64)->i64>>) -> i64 { let i = 0_i64; match f { Some(f) => f(i), None => i, } }
方案3:显式声明泛型参数并指定类型
将impl Fn改为显式泛型参数,调用时通过::<类型>指定具体类型:
fn main(){ let a = apply(Some(|i| i + 1)); let b = apply::<fn(i64)->i64>(None); // 显式指定泛型参数 println!("a: {0}; b: {1}", a, b) } // 显式声明泛型参数F,替代impl Trait语法 fn apply<F: Fn(i64)->i64>(f: Option<F>) -> i64 { let i = 0_i64; match f { Some(f) => f(i), None => i, } }
内容的提问来源于stack exchange,提问作者Bitcoin Eagle
相关产品推荐
相关产品推荐

