以“static”为前缀的闭包是什么意思?我什么时候会使用它?

dro*_*te7 3 static closures rust

我偶然发现了一个在文档中有效的示例static || { }。然而,在我自己的代码中使用这样的表达式的尝试失败了。我想知道为什么。

来自https://doc.rust-lang.org/stable/std/pin/macro.pin.html的例子

#![feature(generators, generator_trait)]
use std::{
    ops::{Generator, GeneratorState},
    pin::pin,
};

fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ {
 // Allow generator to be self-referential (not `Unpin`)
 // vvvvvv        so that locals can cross yield points.
    static || {
        let foo = String::from("foo");
        let foo_ref = &foo; // ------+
        yield 0;                  // | <- crosses yield point!
        println!("{foo_ref}"); // <--+
        yield foo.len();
    }
}

fn main() {
    let mut generator = pin!(generator_fn());
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(0) => {},
        _ => unreachable!(),
    }
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(3) => {},
        _ => unreachable!(),
    }
    match generator.resume(()) {
        GeneratorState::Yielded(_) => unreachable!(),
        GeneratorState::Complete(()) => {},
    }
}
Run Code Online (Sandbox Code Playgroud)

我的尝试失败了:

fn func() -> impl Fn() {
    static || {
        println!("qwerty");
    }
}
Run Code Online (Sandbox Code Playgroud)

出现以下错误:

#![feature(generators, generator_trait)]
use std::{
    ops::{Generator, GeneratorState},
    pin::pin,
};

fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ {
 // Allow generator to be self-referential (not `Unpin`)
 // vvvvvv        so that locals can cross yield points.
    static || {
        let foo = String::from("foo");
        let foo_ref = &foo; // ------+
        yield 0;                  // | <- crosses yield point!
        println!("{foo_ref}"); // <--+
        yield foo.len();
    }
}

fn main() {
    let mut generator = pin!(generator_fn());
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(0) => {},
        _ => unreachable!(),
    }
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(3) => {},
        _ => unreachable!(),
    }
    match generator.resume(()) {
        GeneratorState::Yielded(_) => unreachable!(),
        GeneratorState::Complete(()) => {},
    }
}
Run Code Online (Sandbox Code Playgroud)

生锈版本:

fn func() -> impl Fn() {
    static || {
        println!("qwerty");
    }
}
Run Code Online (Sandbox Code Playgroud)

E_n*_*ate 5

在撰写本文时,Rust 稳定工具链不以任何方式支持静态闭包。您所看到的是不稳定特征生成器的使用,它采用类似闭包的语法来表示生成器函数。引用一些相关部分:

生成器是一个“可恢复函数”,在语法上类似于闭包,但在编译器本身中编译为截然不同的语义。[...]生成器使用yield关键字“返回”,然后调用者可以在yield关键字之后恢复生成器以恢复执行。

[...]

生成器是类似闭包的文字,可以包含yield语句。该yield语句采用一个可选的值表达式来从生成器中产生。所有生成器文字都实现了模块Generator中的特征std::ops

作为一项不稳定的功能,有关其功能的任何细节都可能会发生变化。从 开始,仅当您添加必要的功能属性、使函数返回而不是,并且在生成器中至少包含一个时,nightly-2023-04-02该语法才有效。static || { /* ... */ }impl Generatorimpl Fnyield

#![feature(generators, generator_trait)]
use std::ops::Generator;

fn func() -> impl Generator<Yield = (), Return = ()> {
    static || {
        yield;
        println!("qwerty");
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

也可以看看:

  • 请注意,也有不带“static”的生成器,不同之处在于“static”生成器允许自引用,因此不要实现“Unpin”,而非“static”生成器则不允许自引用。参考,因此实现“Unpin”。 (3认同)