如何将闭包用作另一个闭包的参数?

5
代码如下:
fn main() {
  let arg = | | println!("closure");
  let call_twice = | c | { c(); c(); };
  call_twice(arg);
}

但编译器无法推断参数c的正确类型。错误信息:

error: the type of this value must be known in this context

我该如何告诉编译器参数的类型是一个实现了Fn trait 的泛型类型?


编辑:如果参数类型是 trait object,那么代码可以被编译器接受。但这个间接引用是必要的吗?

fn main() {
  let arg = | | println!("closure");
  let call_twice = | c :&Fn() | { c(); c(); };
  call_twice(&arg);
}

感谢你的回答。但是我被类型推断问题所困扰。使用fn可以让编译器满意。

fn main() {
 let arg = | | println!("closure");

 // now compiler knows the argument `c` is a closure
 fn call_twice<F>(c: F) where F:Fn() {c(); c();}

 call_twice(arg);
}

我们是否可以添加一种语法来支持类似的功能? 例如 for<F> | c:F | where F:Fn() {c(); c();}. 与此类似的IT技术相关内容。

我们能否添加一种语法来支持类似的功能?这不是一个适合在Stack Overflow上提问的问题,你可以在Reddit(r/rust)或Rust论坛上提问。 - Matthieu M.
1个回答

3

按照Rust书中有关返回闭包的部分指南,将闭包转换为move闭包并对其进行封装,这是我必须做的才能在Rust Playground上运行您的程序:

fn main() {
    let arg = Box::new(move || println!("closure"));
    let call_twice = |c: Box<Fn()>| { c(); c(); };
    call_twice(arg);
}

编辑以应对 OP 最近的编辑: 不。你正在处理的问题最终不是类型推断问题。如果只是类型推断,那么我们所要做的就是告诉闭包c是一个闭包。实际问题是 "闭包参数必须是本地变量,所有本地变量的大小必须在编译时已知"。另一方面,Rust函数参数显然没有这个要求。

1
作为一个完全的 Rust 新手,我必须说你编辑中的微小间接比我的解决方案看起来更加简洁。我猜测由于 Rust 在编译时需要已知参数大小,因此无论是装箱还是间接都是绝对必需的。 - Judah Meek
3
这里的“move”是不必要的。 - Matthieu M.
既然这个闭包实际上并没有被返回,那么使用借用将其放在栈上是否比使用盒子将其放在堆上更好呢? - Alex Knauth
@MatthieuM,你说得完全正确。你能解释一下为什么move是不必要的吗?@AlexKnauth,这不就是OP在他的间接编辑中做的基本操作吗? - Judah Meek
1
@JudahMeek:只有在(1)捕获变量且(2)您无法长时间借用其中之一时,“move”才是必要的。在这里,您没有捕获任何变量,因此不必要。 - Matthieu M.
你可以使用 |c: &Fn()| 代替 |c: Box<Fn()>|。需要注意的是,你必须这样调用它:call_twice(&*arg); - senia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接