rust异步编程:生成器

标准库代码位于https://github.com/rust-lang/rust/tree/master/library
这里使用目前最新版本1.45.2

概述

生成器是rust协程(异步编程)实现的基础,async代码最终会编译成生成器,一个生成器就是一个可恢复函数,生成器和闭包比较相似,但在编译器中会将生成器编译成截然不同的语义。生成器最大的特点就是,程序的执行流程可以在生成器和调用者之间来回切换。当我们需要暂时从生成器中返回的时候,就使用yield关键字;当调用者希望再次进入生成器的时候,就调用resume方法,这时程序执行的流程是从上次yield返回的那个点继续执行 ,它可以保证代码不会重复执行,恢复执行时能获取到上一次变量的值。

标准库

std::ops::{Generator, GeneratorState}

src/libcore/ops/generator.rs

#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[lang = "generator_state"]
pub enum GeneratorState<Y, R> {
    Yielded(Y),
    Complete(R),
}

#[lang = "generator"]
#[fundamental]
pub trait Generator<R = ()> {
    type Yield;
    type Return;
    fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
}

可以看到标准库提供的enum和trait分别用generator_state和generator标识,这说明编译器会做特殊处理。

和闭包的关系

一个简单的生成器例子,可以看出来和闭包没什么不同,就多了一个闭包里没见过的yield关键词

#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn main() {
    let mut generator = || {
        yield 1;
        return "foo"
    };

    match Pin::new(&mut generator).resume(()) {
        GeneratorState::Yielded(1) => {}
        _ => panic!("unexpected value from resume"),
    }
    match Pin::new(&mut generator).resume(()) {
        GeneratorState::Complete("foo") => {}
        _ => panic!("unexpected value from resume"),
    }
}
  • 生成器和闭包类似,只不过多了一个yield关键词
  • 可以多次调用resume ,这又和迭代器类似(惰性)
  • 和闭包一样可以捕获外部环境的变量,也可以使用move关键字将变量所有权移动到生成器中。每当生成器被drop时,它将drop掉所有捕获的环境变量。
  • 生成器自动实现了Send和Sync,但不会自动实现Copy或Clone之类的trait
生成的代码究竟是啥样?

在编译器中,生成器编译成状态机。每个yield表达式对应一个不同的状态.
再看一个例子

#![feature(generators, generator_trait)]

use std::ops::Generator;
use std::pin::Pin;

fn main() {
    let ret = "foo";
    let mut generator = move || {
        yield 1;
        return ret
    };

    Pin::new(&mut generator).resume(());
    Pin::new(&mut generator).resume(());
}

上面的例子编译器翻译后的代码大概是这样子:

#![feature(arbitrary_self_types, generators, generator_trait)]

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn main() {
    let ret = "foo";
    let mut generator = {
        enum __Generator {
            Start(&'static str),
            Yield1(&'static str),
            Done,
        }

        impl Generator for __Generator {
            type Yield = i32;
            type Return = &'static str;

            fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> {
                use std::mem;
                match mem::replace(&mut *self, __Generator::Done) {
                    __Generator::Start(s) => {
                        *self = __Generator::Yield1(s);
                        GeneratorState::Yielded(1)
                    }

                    __Generator::Yield1(s) => {
                        *self = __Generator::Done;
                        GeneratorState::Complete(s)
                    }

                    __Generator::Done => {
                        panic!("generator resumed after completion")
                    }
                }
            }
        }

        __Generator::Start(ret)
    };

    Pin::new(&mut generator).resume(());
    Pin::new(&mut generator).resume(());
}

编译器生成器相关源码:
src/librustc_mir/transform/generator.rs
src/librustc_ast_lowering/expr.rs

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值