Futures 0.1中使用组合子.如果你曾经是用过Javascript中的Promises,那么你已经比较熟悉combinators了. 在Rust中,他们看起来如下:let future = Connection::connect(conn_str).and_then(|conn| {conn.query("somerequest").map(|row|{SomeStruct::from(row)}).collect::<Vec<SomeStruct>>()});let rows: Result<Vec<SomeStruct>, SomeLibraryError> = block_on(future);
async fn myfn() {let text = String::from("Hello world");let borrowed = &text[0..5];somefuture.await;println!("{}", borrowed);}
#![feature(generators, generator_trait)]use std::ops::{Generator, GeneratorState};fn main() {let a: i32 = 4;let mut gen = move || {println!("Hello");yield a * 2;println!("world!");};if let GeneratorState::Yielded(n) = gen.resume() {println!("Got value {}", n);}if let GeneratorState::Complete(()) = gen.resume() {()};}早些时候,在人们对 Pin 的设计达成共识之前,编译完代码看起来类似于这样:
fn main() {let mut gen = GeneratorA::start(4);if let GeneratorState::Yielded(n) = gen.resume() {println!("Got value {}", n);}if let GeneratorState::Complete(()) = gen.resume() {()};}// If you've ever wondered why the parameters are called Y and R the naming from// the original rfc most likely holds the answerenum GeneratorState<Y, R> {Yielded(Y), // originally called `Yield(Y)`Complete(R), // originally called `Return(R)`}trait Generator {type Yield;type Return;fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;}enum GeneratorA {Enter(i32),Yield1(i32),Exit,}impl GeneratorA {fn start(a1: i32) -> Self {GeneratorA::Enter(a1)}}impl Generator for GeneratorA {type Yield = i32;type Return = ();fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {// lets us get ownership over current statematch std::mem::replace(self, GeneratorA::Exit) {GeneratorA::Enter(a1) => {/*----code before yield----*/println!("Hello");let a = a1 * 2;*self = GeneratorA::Yield1(a);GeneratorState::Yielded(a)}GeneratorA::Yield1(_) => {/*-----code after yield-----*/println!("world!");*self = GeneratorA::Exit;GeneratorState::Complete(())}GeneratorA::Exit => panic!("Can't advance an exited generator!"),}}}
Futures 0.1,所以我们不能让这个限制存在。我们将使用目前 Rust 中使用的状态机的优化版本。更深入的解释见 Tyler Mandry 的文章: Rust 如何优化async/await
let mut generator = move || {let to_borrow = String::from("Hello");let borrowed = &to_borrow;yield borrowed.len();println!("{} world!", borrowed);};我们将手工编写一些版本的状态机,这些状态机表示生成器定义的状态机。
while let Some(val) = generator.next() {println!("{}", val);}
#![allow(unused_variables)]fn main() {enum GeneratorState<Y, R> {Yielded(Y),Complete(R),}trait Generator {type Yield;type Return;fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;}enum GeneratorA {Enter,Yield1 {to_borrow: String,borrowed: &String, // uh, what lifetime should this have?},Exit,}impl GeneratorA {fn start() -> Self {GeneratorA::Enter}}impl Generator for GeneratorA {type Yield = usize;type Return = ();fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {// lets us get ownership over current statematch std::mem::replace(self, GeneratorA::Exit) {GeneratorA::Enter => {let to_borrow = String::from("Hello");let borrowed = &to_borrow; // <--- NB!let res = borrowed.len();*self = GeneratorA::Yield1 {to_borrow, borrowed};GeneratorState::Yielded(res)}GeneratorA::Yield1 {to_borrow, borrowed} => {println!("Hello {}", borrowed);*self = GeneratorA::Exit;GeneratorState::Complete(())}GeneratorA::Exit => panic!("Can't advance an exited generator!"),}}}}
#![allow(unused_variables)]fn main() {enum GeneratorState<Y, R> {Yielded(Y),Complete(R),}trait Generator {type Yield;type Return;fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;}enum GeneratorA {Enter,Yield1 {to_borrow: String,borrowed: *const String, // NB! This is now a raw pointer!},Exit,}impl GeneratorA {fn start() -> Self {GeneratorA::Enter}}impl Generator for GeneratorA {type Yield = usize;type Return = ();fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {match self {GeneratorA::Enter => {let to_borrow = String::from("Hello");let borrowed = &to_borrow;let res = borrowed.len();*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};// NB! And we set the pointer to reference the to_borrow string hereif let GeneratorA::Yield1 {to_borrow, borrowed} = self {*borrowed = to_borrow;}GeneratorState::Yielded(res)}GeneratorA::Yield1 {borrowed, ..} => {let borrowed: &String = unsafe {&**borrowed};println!("{} world", borrowed);*self = GeneratorA::Exit;GeneratorState::Complete(())}GeneratorA::Exit => panic!("Can't advance an exited generator!"),}}}}
let mut gen = move || {let to_borrow = String::from("Hello");let borrowed = &to_borrow;yield borrowed.len();println!("{} world!", borrowed);};
pub fn main() {let mut gen = GeneratorA::start();let mut gen2 = GeneratorA::start();if let GeneratorState::Yielded(n) = gen.resume() {println!("Got value {}", n);}if let GeneratorState::Yielded(n) = gen2.resume() {println!("Got value {}", n);}if let GeneratorState::Complete(()) = gen.resume() {()};}enum GeneratorState<Y, R> {Yielded(Y),Complete(R),}trait Generator {type Yield;type Return;fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;}enum GeneratorA {Enter,Yield1 {to_borrow: String,borrowed: *const String,},Exit,}impl GeneratorA {fn start() -> Self {GeneratorA::Enter}}impl Generator for GeneratorA {type Yield = usize;type Return = ();fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {match self {GeneratorA::Enter => {let to_borrow = String::from("Hello");let borrowed = &to_borrow;let res = borrowed.len();*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};// We set the self-reference hereif let GeneratorA::Yield1 {to_borrow, borrowed} = self {*borrowed = to_borrow;}GeneratorState::Yielded(res)}GeneratorA::Yield1 {borrowed, ..} => {let borrowed: &String = unsafe {&**borrowed};println!("{} world", borrowed);*self = GeneratorA::Exit;GeneratorState::Complete(())}GeneratorA::Exit => panic!("Can't advance an exited generator!"),}}}
#![feature(never_type)] // Force nightly compiler to be used in playground// by betting on it's true that this type is named after it's stabilization date...pub fn main() {let mut gen = GeneratorA::start();let mut gen2 = GeneratorA::start();if let GeneratorState::Yielded(n) = gen.resume() {println!("Got value {}", n);}std::mem::swap(&mut gen, &mut gen2); // <--- Big problem!if let GeneratorState::Yielded(n) = gen2.resume() {println!("Got value {}", n);}// This would now start gen2 since we swapped them.if let GeneratorState::Complete(()) = gen.resume() {()};}enum GeneratorState<Y, R> {Yielded(Y),Complete(R),}trait Generator {type Yield;type Return;fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;}enum GeneratorA {Enter,Yield1 {to_borrow: String,borrowed: *const String,},Exit,}impl GeneratorA {fn start() -> Self {GeneratorA::Enter}}impl Generator for GeneratorA {type Yield = usize;type Return = ();fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {match self {GeneratorA::Enter => {let to_borrow = String::from("Hello");let borrowed = &to_borrow;let res = borrowed.len();*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};// We set the self-reference hereif let GeneratorA::Yield1 {to_borrow, borrowed} = self {*borrowed = to_borrow;}GeneratorState::Yielded(res)}GeneratorA::Yield1 {borrowed, ..} => {let borrowed: &String = unsafe {&**borrowed};println!("{} world", borrowed);*self = GeneratorA::Exit;GeneratorState::Complete(())}GeneratorA::Exit => panic!("Can't advance an exited generator!"),}}}运行代码并比较结果。你看到问题了吗?
let mut gen = move || {let to_borrow = String::from("Hello");let borrowed = &to_borrow;yield borrowed.len();println!("{} world!", borrowed);};
let mut fut = async {let to_borrow = String::from("Hello");let borrowed = &to_borrow;SomeResource::some_task().await;println!("{} world!", borrowed);};
Generator::resume,而是调用 Future::poll,并且不返回 generated 或 Complete,而是返回 Pending 或 Ready。Future中的每一个await就像生成器中的一个yield。要注意的是,API可能会发生改变。在我撰写本书时,生成器API有一个更改,添加了对“ resume”参数的支持,以便传递到生成器闭包中。
可以关注RFC#033的相关问题#4312的进展。
#![feature(generators, generator_trait)]use std::ops::{Generator, GeneratorState};pub fn main() {let gen1 = static || {let to_borrow = String::from("Hello");let borrowed = &to_borrow;yield borrowed.len();println!("{} world!", borrowed);};let gen2 = static || {let to_borrow = String::from("Hello");let borrowed = &to_borrow;yield borrowed.len();println!("{} world!", borrowed);};let mut pinned1 = Box::pin(gen1);let mut pinned2 = Box::pin(gen2);if let GeneratorState::Yielded(n) = pinned1.as_mut().resume(()) {println!("Gen1 got value {}", n);}if let GeneratorState::Yielded(n) = pinned2.as_mut().resume(()) {println!("Gen2 got value {}", n);};let _ = pinned1.as_mut().resume(());let _ = pinned2.as_mut().resume(());}
原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。