Что означает закрытие с префиксом `static`? И когда бы я его использовал?

Я наткнулся на пример с 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(()) => {},
    }
}

моя попытка, которая терпит неудачу:

fn func() -> impl Fn() {
    static || {
        println!("qwerty");
    }
}

со следующей ошибкой:

error[E0697]: closures cannot be static
 --> ./ex_099.rs:2:5
  |
2 |     static || {
  |     ^^^^^^^^^

версия ржавчины:

$ rustc --version
rustc 1.70.0-nightly (88fb1b922 2023-04-10)
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
3
0
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

На момент написания статьи стабильная цепочка инструментов Rust никоим образом не поддерживает статическое замыкание. То, что вы видите, — это использование нестабильной функции генераторов, которая прибегает к синтаксису, подобному замыканию, для представления функций генератора. Цитирование нескольких соответствующих частей:

Генератор — это «возобновляемая функция», которая синтаксически напоминает замыкание, но компилируется в самом компиляторе с совершенно другой семантикой. [...] Генераторы используют ключевое слово yield для «возврата», а затем вызывающий абонент может возобновить работу генератора, чтобы возобновить выполнение сразу после ключевого слова yield.

[...]

Генераторы — это литералы, похожие на замыкание, которые могут содержать оператор yield. Оператор yield принимает необязательное выражение значения, которое нужно вывести из генератора. Все литералы генератора реализуют трейт Generator в модуле std::ops

Поскольку функция нестабильна, любые сведения о ее функционировании могут быть изменены. Начиная с nightly-2023-04-02, синтаксис static || { /* ... */ } будет работать только в том случае, если вы добавите необходимые атрибуты функций, заставите функцию возвращать impl Generator вместо impl Fn и включите хотя бы один yield в генератор.

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

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

Детская площадка

Смотрите также:

Обратите внимание, что есть также генераторы без static, и разница в том, что генераторы static могут быть самореферентными и, следовательно, не реализуют Unpin, в то время как не-static генераторы не могут быть самореферентными и, следовательно, реализуют Unpin.

Chayim Friedman 11.04.2023 15:12

Другие вопросы по теме