Я наткнулся на пример с 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)
На момент написания статьи стабильная цепочка инструментов 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
.