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