从函数返回闭包

时间:2014-08-22 11:18:22

标签: rust

注意:在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

如果我理解正确,则关闭是未装箱的,因此它拥有ab。我觉得它需要一辈子似乎很奇怪。我该如何解决这个问题?

3 个答案:

答案 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
    }
}

这允许返回未装箱的闭包,即使无法指定闭包的确切类型。

如果其中任何一个属实,会帮助您:

  1. 您在此版本之前定位Rust

  2. 你的职能有任何条件:

    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();
    }
    

    这里没有一种返回类型;每个封口都有一种独特的,不可媲美的类型。

  3. 您需要能够出于任何原因命名返回的类型:

    impl SomeTrait

    您不能(yet)使用{{1}}作为变量类型。

  4. 在这些情况下,您需要使用间接。常见的解决方案是特征对象,如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 RFCits 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}}。)