【问题标题】:Why does a generator that was working in nightly Rust 1.29 give an error in nightly 1.34.0?为什么在 nightly Rust 1.29 中工作的生成器在 nightly 1.34.0 中会出错?
【发布时间】:2019-06-18 22:32:09
【问题描述】:

我正在使用 Rust 生成器,它在夜间 1.29.0 中运行良好:

#![feature(generators, generator_trait)]

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

fn main() {
    let mut generator: Box<dyn Generator<Yield = u64, Return = &str>> = Box::new(move || {
        yield 1;
        return "foo";
    });

    unsafe {
        match generator.resume() {
            GeneratorState::Yielded(1) => {
                println!("Yielded");
            }
            _ => panic!("unexpected return from resume"),
        }
        match generator.resume() {
            GeneratorState::Complete("foo") => {
                println!("Completed");
            }
            _ => panic!("unexpected return from resume"),
        }
    }
}

但是,夜间版本 1.34.0 要求将 Generator 包裹在 Pin 中,但是当我将 Generator 包裹到 Pin 中时,代码不再起作用。

#![feature(generators, generator_trait)]

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

fn main() {
    let mut generator: Box<dyn Generator<Yield = u64, Return = &str>> = Box::new(move || {
        yield 1;
        return "foo";
    });

    match Pin::new(&mut generator).resume() {
        GeneratorState::Yielded(1) => {
            println!("Yielded");
        }
        _ => panic!("unexpected return from resume"),
    }
    match Pin::new(&mut generator).resume() {
        GeneratorState::Complete("foo") => {
            println!("Completed");
        }
        _ => panic!("unexpected return from resume"),
    }
}

并且代码给出了以下错误。

error[E0599]: no method named `resume` found for type `std::pin::Pin<&mut std::boxed::Box<dyn std::ops::Generator<Yield = u64, Return = &str>>>` in the current scope
  --> src/main.rs:12:36
   |
12 |     match Pin::new(&mut generator).resume() {
   |                                    ^^^^^^
   |
   = note: the method `resume` exists but the following trait bounds were not satisfied:
           `std::boxed::Box<dyn std::ops::Generator<Yield = u64, Return = &str>> : std::ops::Generator`

当我删除生成器的类型时,它工作正常:

let mut generator = Box::new(move || {
        yield 1;
        return "foo"
});

我有几个问题:

  • 为什么在最新版本中将Generator 包裹在Pin 中会出现错误?
  • 生成器使用Pin有什么用(因为它会阻止指针的值被移动),我不明白PinGenerator之间的关系?
  • 为什么当我们删除 generator 变量的类型时代码会起作用?
  • 为什么resume 方法不再是unsafe

【问题讨论】:

    标签: rust generator


    【解决方案1】:

    为什么在 Nightly Rust 1.29 中运行的生成器代码在 Nightly 1.34.0 中会出错?

    因为这是一个每晚不稳定的功能,它可能随时改变并且它改变了。

    另见:

    为什么将Generator 包装在Pin 中会在最新版本中出现错误?

    如错误消息所述,Box&lt;dyn Generator&lt;Yield = u64, Return = &amp;str&gt;&gt; 未实现 Generator

    另见:

    生成器使用Pin 有什么用?

    为什么resume 方法不再不安全?

    resume 方法是不安全的,因为如果生成器有一个自引用变量并且它在两次调用 resume 之间移动,您可能会引入内存不安全。 Pin 阻止移动,从而消除了不安全性。这是将不安全逻辑包装在仅公开安全接口的 API 中的经典示例。

    另见:

    当我们删除生成器变量的类型时,为什么代码可以工作?

    因为它不再是一个 trait 对象 (Box&lt;dyn Generator&gt;),而只是一个盒装的混凝土生成器。

    另见:


    我会这样写

    #![feature(generators, generator_trait)]
    
    use std::ops::{Generator, GeneratorState};
    
    fn main() {
        let mut generator = Box::pin(move || {
            yield 1;
            "foo"
        });
    
        match generator.as_mut().resume() {
            GeneratorState::Yielded(1) => println!("Yielded"),
            _ => panic!("unexpected return from resume"),
        }
        match generator.as_mut().resume() {
            GeneratorState::Complete("foo") => println!("Completed"),
            _ => panic!("unexpected return from resume"),
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2022-12-04
      • 2018-05-23
      • 2019-01-01
      • 2020-04-17
      • 2017-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      相关资源
      最近更新 更多