如何编写以接收闭包为参数的闭包作为参数的Rust函数?
问题描述
我想编写一个函数,它接收一个闭包作为参数,而这个闭包又以另一个闭包作为参数。示例代码如下:
fn test<F: Fn(G), G: Fn()>(f: F) { let print = || { println!("hello"); }; f(print); } fn main() { test(|print| { print(); }) }
但这段代码编译时会报如下错误:
error[E0308]: 类型不匹配 --> src/main.rs:5:7 | 1 | fn test<F: Fn(G), G: Fn()>(f: F) { | - 期望的是这个类型参数 2 | let print = || { | -- 找到的闭包 ... 5 | f(print); | - ^^^^^ 期望类型参数 `G`,找到闭包 | | | 此函数的参数不正确 | = note: 期望类型参数 `G` 找到闭包 `{closure@src/main.rs:2:17: 2:19}`
错误原因
原代码的泛型约束逻辑搞反了:G是由调用者传入的闭包F决定的类型参数,但函数内部创建的print是一个具体的匿名闭包类型,无法匹配调用者指定的任意G类型,因此触发类型不匹配错误。
解决方案
我们需要调整泛型约束,让F能接受任意实现Fn()的闭包,而非绑定到某个特定的G类型,以下是几种可行写法:
方法1:使用impl Trait简化约束
这是最简洁的写法,直接声明F可以接受任意实现Fn()的类型作为参数:
fn test<F>(f: F) where F: Fn(impl Fn()), { let print = || { println!("hello"); }; f(print); } fn main() { test(|print| { print(); }); }
方法2:明确泛型约束关系
如果需要更清晰的泛型声明,可以将G的约束绑定到F的参数要求上,同时指定内部闭包的类型:
fn test<F, G>(f: F) where G: Fn(), F: Fn(G), { let print: G = || { println!("hello"); }; f(print); } fn main() { test(|print| { print(); }); }
这种写法下,G由调用者的闭包推导而来,内部的print闭包必须与该类型一致。
方法3:使用 trait 对象(动态分发)
如果需要更大的灵活性,允许f接受不同类型的闭包,可以使用Box<dyn Fn()> trait 对象,代价是轻微的运行时开销:
fn test<F>(f: F) where F: Fn(Box<dyn Fn()>), { let print = Box::new(|| { println!("hello"); }); f(print); } fn main() { test(|print| { print(); }); }
内容的提问来源于stack exchange,提问作者Piotr Wach
相关产品推荐
相关产品推荐

