从函数返回闭包
最后,无箱封锁已经降落,所以我正在试验他们看看你能做什么。
我有这个简单的function:
fn make_adder(a: int, b: int) -> || -> int { || a + b }
但是,我得到一个missing lifetime specifier [E0106]
错误。 我试图通过将返回types更改为||: 'static -> int
来解决此问题,但是cannot infer an appropriate lifetime due to conflicting requirements
,我得到另一个错误cannot infer an appropriate lifetime due to conflicting requirements
。
如果我理解正确,封闭是unboxed,所以它拥有a
和b
。 对我来说,这似乎很奇怪,它需要一生。 我该如何解决这个问题?
至于PR#35091 (现在只能在夜间使用Rust),您可以使用impl trait
:
#![feature(conservative_impl_trait)] fn make_adder(a: i32) -> impl Fn(i32) -> i32 { move |b| a + b } fn main() { println!("{}", make_adder(1)(2)); }
这允许返回一个未装箱的闭包,即使不可能指定闭包的确切types。
如果你在你的函数中有任何条件,这将不会对你有所帮助:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 { if a > 0 { move |b| a + b } else { move |b| a - b } }
这里没有一个返回types, 每个封闭都有一个独特的,不可闻的types。 在这种情况下,您需要使用间接。 常见的解决scheme是特质对象 ,如其他答案中所述 。
可以返回Box
es中的闭包,也就是作为实现某些特征的特征对象:
fn make_adder(a: i32) -> Box<Fn(i32) -> i32> { Box::new(move |b| a + b) } fn main() { println!("{}", make_adder(1)(2)); }
( 在这里试试)
还有一个关于添加无盒抽象返回types的RFC ( 它的跟踪问题 ),它允许按值返回闭包,没有框,但是这个RFC被推迟了。 根据该RFC中的讨论,最近似乎有一些工作已经完成,所以可能相对较快的是取消装箱的抽象返回types。
||
语法仍然是旧的盒装闭包,所以这不起作用的原因以前没有。
而且,即使使用正确的盒装闭包语法|&:| -> int
也不行 |&:| -> int
,因为它是字面上只是某些特质的糖。 目前,糖的语法是|X: args...| -> ret
|X: args...| -> ret
,其中X
可以是&
, &mut
或者什么也不是,对应于Fn
, FnMut
, FnOnce
特征,你也可以为非加糖forms写Fn<(args...), ret>
等。 糖可能会改变(可能像Fn(args...) -> ret
)。
每一个unboxed闭包都有一个由编译器在内部生成的唯一的,无名的types:讨论unboxed闭包的唯一方法是通过generics和特征边界。 特别是写作
fn make_adder(a: int, b: int) -> |&:| -> int { |&:| a + b }
就像写作一样
fn make_adder(a: int, b: int) -> Fn<(), int> { |&:| a + b }
即说make_adder
返回一个make_adder
特性值; 这在目前没什么意义。 首先要尝试的是
fn make_adder<F: Fn<(), int>>(a: int, b: int) -> F { |&:| a + b }
但是这是说make_adder
返回调用者select的任何F
,而我们要说它返回一些固定的(但“隐藏”)types。 这需要抽象返回types ,基本上说,“返回值实现这个特性”,同时仍然被拆箱和静态parsing。 在那个(暂时closures的)RFC的语言中,
fn make_adder(a: int, b: int) -> impl Fn<(), int> { |&:| a + b }
或者与closures糖。
(另一个小问题是:我对解封封闭并不十分确定,但旧封闭当然仍然是通过引用来捕获的东西,这是另一回事,就是这个问题中提出的代码,这已经在#16610中得到纠正。