fixed some of the generator examples that were a bit unprecise
This commit is contained in:
@@ -80,7 +80,7 @@ async/await as keywords (it can even be done using a macro).
|
|||||||
2. No need for context switching and saving/restoring CPU state
|
2. No need for context switching and saving/restoring CPU state
|
||||||
3. No need to handle dynamic stack allocation
|
3. No need to handle dynamic stack allocation
|
||||||
4. Very memory efficient
|
4. Very memory efficient
|
||||||
5. Allowed for borrows across suspension points
|
5. Allows us to borrow across suspension points
|
||||||
|
|
||||||
The last point is in contrast to `Futures 1.0`. With async/await we can do this:
|
The last point is in contrast to `Futures 1.0`. With async/await we can do this:
|
||||||
|
|
||||||
@@ -101,24 +101,30 @@ require any increased memory at all.
|
|||||||
## How generators work
|
## How generators work
|
||||||
|
|
||||||
In Nightly Rust today you can use the `yield` keyword. Basically using this
|
In Nightly Rust today you can use the `yield` keyword. Basically using this
|
||||||
keyword in a closure, converts it to a generator. A closure looking like this
|
keyword in a closure, converts it to a generator. A closure could look like this
|
||||||
(I'm going to use the terminology that's currently in Rust):
|
before we had a concept of `Pin`:
|
||||||
|
|
||||||
|
|
||||||
```rust,noplaypen,ignore
|
```rust,noplaypen,ignore
|
||||||
let a = 4;
|
#![feature(generators, generator_trait)]
|
||||||
let b = move || {
|
use std::ops::{Generator, GeneratorState};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a: i32 = 4;
|
||||||
|
let mut gen = move || {
|
||||||
println!("Hello");
|
println!("Hello");
|
||||||
yield a * 2;
|
yield a * 2;
|
||||||
println!("world!");
|
println!("world!");
|
||||||
};
|
};
|
||||||
|
|
||||||
if let GeneratorState::Yielded(n) = gen.resume() {
|
if let GeneratorState::Yielded(n) = gen.resume() {
|
||||||
println!("Got value {}", n);
|
println!("Got value {}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let GeneratorState::Complete(()) = gen.resume() {
|
if let GeneratorState::Complete(()) = gen.resume() {
|
||||||
()
|
()
|
||||||
};
|
};
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Early on, before there was a consensus about the design of `Pin`, this
|
Early on, before there was a consensus about the design of `Pin`, this
|
||||||
@@ -206,18 +212,17 @@ We could forbid that, but **one of the major design goals for the async/await sy
|
|||||||
to allow this**. These kinds of borrows were not possible using `Futures 1.0` so we can't let this
|
to allow this**. These kinds of borrows were not possible using `Futures 1.0` so we can't let this
|
||||||
limitation just slip and call it a day yet.
|
limitation just slip and call it a day yet.
|
||||||
|
|
||||||
Instead of discussing it in theory, let's look at some code.
|
Instead of discussing it in theory, let's look at some code.
|
||||||
|
|
||||||
> We'll use the optimized version of the state machines which is used in Rust today. For a more
|
> We'll use the optimized version of the state machines which is used in Rust today. For a more
|
||||||
> in deapth explanation see [Tyler Mandry's excellent article: How Rust optimizes async/await][optimizing-await]
|
> in depth explanation see [Tyler Mandry's excellent article: How Rust optimizes async/await][optimizing-await]
|
||||||
|
|
||||||
```rust,noplaypen,ignore
|
```rust,noplaypen,ignore
|
||||||
let a = 4;
|
let mut gen = move || {
|
||||||
let b = move || {
|
let to_borrow = String::from("Hello");
|
||||||
let to_borrow = String::new("Hello");
|
|
||||||
let borrowed = &to_borrow;
|
let borrowed = &to_borrow;
|
||||||
println!("{}", borrowed);
|
println!("{}", borrowed);
|
||||||
yield a * 2;
|
yield borrowed.len();
|
||||||
println!("{} world!", borrowed);
|
println!("{} world!", borrowed);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -263,8 +268,10 @@ impl Generator for GeneratorA {
|
|||||||
GeneratorA::Enter => {
|
GeneratorA::Enter => {
|
||||||
let to_borrow = String::from("Hello");
|
let to_borrow = String::from("Hello");
|
||||||
let borrowed = &to_borrow;
|
let borrowed = &to_borrow;
|
||||||
|
let res = borrowed.len();
|
||||||
|
|
||||||
*self = GeneratorA::Yield1 {to_borrow, borrowed};
|
*self = GeneratorA::Yield1 {to_borrow, borrowed};
|
||||||
GeneratorState::Yielded(borrowed.len())
|
GeneratorState::Yielded(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratorA::Yield1 {to_borrow, borrowed} => {
|
GeneratorA::Yield1 {to_borrow, borrowed} => {
|
||||||
@@ -383,7 +390,7 @@ But now, let's prevent this problem using `Pin`. We'll discuss
|
|||||||
reading the comments.
|
reading the comments.
|
||||||
|
|
||||||
```rust,editable
|
```rust,editable
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)] // needed to implement `!Unpin`
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@@ -407,7 +414,7 @@ pub fn main() {
|
|||||||
//let mut pinned2 = unsafe { Pin::new_unchecked(&mut gen2) };
|
//let mut pinned2 = unsafe { Pin::new_unchecked(&mut gen2) };
|
||||||
|
|
||||||
if let GeneratorState::Yielded(n) = pinned1.as_mut().resume() {
|
if let GeneratorState::Yielded(n) = pinned1.as_mut().resume() {
|
||||||
println!("Got value {}", n);
|
println!("Gen1 got value {}", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let GeneratorState::Yielded(n) = pinned2.as_mut().resume() {
|
if let GeneratorState::Yielded(n) = pinned2.as_mut().resume() {
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ articles I've already linked to in the book, here are some of my suggestions:
|
|||||||
|
|
||||||
[Jon Gjengset's video on The Why, What and How of Pinning in Rust](https://youtu.be/DkMwYxfSYNQ)
|
[Jon Gjengset's video on The Why, What and How of Pinning in Rust](https://youtu.be/DkMwYxfSYNQ)
|
||||||
|
|
||||||
|
[Withoutboats blog series about async/await](https://boats.gitlab.io/blog/post/2018-01-25-async-i-self-referential-structs/)
|
||||||
|
|
||||||
[condvar_std]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html
|
[condvar_std]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html
|
||||||
[condvar_wiki]: https://en.wikipedia.org/wiki/Monitor_(synchronization)#Condition_variables
|
[condvar_wiki]: https://en.wikipedia.org/wiki/Monitor_(synchronization)#Condition_variables
|
||||||
[arcwake]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.13/futures/task/trait.ArcWake.html
|
[arcwake]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.13/futures/task/trait.ArcWake.html
|
||||||
Reference in New Issue
Block a user