注意:这个问题是在Rust第一次稳定发布之前提出的.之后发生了很多变化,函数中使用的语法甚至不再有效.尽管如此,Shepmaster的答案仍然非常出色,这使得这个问题值得保留.
最后,未装箱的封闭装置着陆了,所以我正在试验它们,看看你能做些什么.
我有这个简单的功能:
fn make_adder(a: int, b: int) -> || -> int {
|| a + b
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到了一个missing lifetime specifier [E0106]错误.我试图通过将返回类型更改为修复此问题||: 'static -> int,但后来又出现了另一个错误cannot infer an appropriate lifetime due to conflicting requirements.
如果我理解正确,关闭是未装箱的,所以它拥有a和b.我觉得它需要一辈子似乎很奇怪.我怎样才能解决这个问题?
She*_*ter 30
从Rust 1.26开始,您可以使用impl trait:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
move |b| a + b
}
fn main() {
println!("{}", make_adder(1)(2));
}
Run Code Online (Sandbox Code Playgroud)
这允许返回未装箱的闭包,即使无法指定闭包的确切类型.
这会不会帮助你,如果任何的这些都是真的:
您在此版本之前定位Rust
你的函数有任何条件:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
if a > 0 {
move |b| a + b
} else {
move |b| a - b
}
}
Run Code Online (Sandbox Code Playgroud)
这里没有一种返回类型; 每个封口都有一种独特的,不可媲美的类型.
您需要能够出于任何原因命名返回的类型:
struct Example<F>(F);
fn make_it() -> Example<impl Fn()> {
Example(|| println!("Hello"))
}
fn main() {
let unnamed_type_ok = make_it();
let named_type_bad: /* No valid type here */ = make_it();
}
Run Code Online (Sandbox Code Playgroud)
您不能将其impl SomeTrait用作变量类型.
在这些情况下,您需要使用间接.常见的解决方案是特质对象,如另一个答案中所述.
Vla*_*eev 25
可以在Boxes中返回闭包,也就是说,作为实现某些特征的特征对象:
fn make_adder(a: i32) -> Box<Fn(i32) -> i32> {
Box::new(move |b| a + b)
}
fn main() {
println!("{}", make_adder(1)(2));
}
Run Code Online (Sandbox Code Playgroud)
(在这里试试)
还有一个关于添加未装箱的抽象返回类型的RFC(它的跟踪问题),它允许按值返回闭包,没有框,但是这个RFC被推迟了.根据RFC中的讨论,似乎最近已经完成了一些工作,因此有可能相对较快地提供未装箱的抽象返回类型.
该||语法仍然是旧盒装关闭,所以这不会为以前不一样工作的原因所在。
而且,即使使用正确的盒装闭包语法也不起作用|&:| -> int,因为它实际上只是某些特征的糖。目前,糖的语法是|X: args...| -> ret,其中X可以是&,&mut或者什么都没有,对应于Fn, FnMut,FnOnce特征,你也可以Fn<(args...), ret>为非糖形式写等。糖可能会发生变化(可能类似于Fn(args...) -> ret)。
每个未装箱的闭包都有一个由编译器内部生成的唯一的、不可命名的类型:谈论未装箱的闭包的唯一方法是通过泛型和特征边界。特别是,写
fn make_adder(a: int, b: int) -> |&:| -> int {
|&:| a + b
}
Run Code Online (Sandbox Code Playgroud)
就像写作
fn make_adder(a: int, b: int) -> Fn<(), int> {
|&:| a + b
}
Run Code Online (Sandbox Code Playgroud)
即说make_adder返回一个未装箱的特征值;目前这没有多大意义。首先要尝试的是
fn make_adder<F: Fn<(), int>>(a: int, b: int) -> F {
|&:| a + b
}
Run Code Online (Sandbox Code Playgroud)
但是这是说,make_adder是返回任何F的主叫方选,而我们想说它返回一些固定的(但“隐藏”)类型。这需要抽象返回类型,基本上说,“返回值实现了这个特征”,同时仍然被拆箱和静态解析。用那个(暂时关闭的)RFC 的语言,
fn make_adder(a: int, b: int) -> impl Fn<(), int> {
|&:| a + b
}
Run Code Online (Sandbox Code Playgroud)
或者用封糖。
(另一个小问题:我对未装箱的闭包不是 100% 确定,但旧的闭包肯定仍然通过引用捕获事物,这是另一个使问题中提出的代码下沉的事情。这在#16610 中得到纠正。)