mirror of https://github.com/rust-lang/async-book
fixed editions and ignoring
This commit is contained in:
parent
658ce12b21
commit
d7651bb1cd
|
@ -30,7 +30,7 @@ must register `wake` to be called when data becomes ready on the socket,
|
|||
which will tell the executor that our future is ready to make progress.
|
||||
A simple `SocketRead` future might look something like this:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_02_future_trait/src/lib.rs:socket_read}}
|
||||
```
|
||||
|
||||
|
@ -39,7 +39,7 @@ operations without needing intermediate allocations. Running multiple futures
|
|||
at once or chaining futures together can be implemented via allocation-free
|
||||
state machines, like this:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_02_future_trait/src/lib.rs:join}}
|
||||
```
|
||||
|
||||
|
@ -47,7 +47,7 @@ This shows how multiple futures can be run simultaneously without needing
|
|||
separate allocations, allowing for more efficient asynchronous programs.
|
||||
Similarly, multiple sequential futures can be run one after another, like this:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_02_future_trait/src/lib.rs:and_then}}
|
||||
```
|
||||
|
||||
|
@ -56,12 +56,12 @@ control flow without requiring multiple allocated objects and deeply nested
|
|||
callbacks. With the basic control-flow out of the way, let's talk about the
|
||||
real `Future` trait and how it is different.
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_02_future_trait/src/lib.rs:real_future}}
|
||||
```
|
||||
|
||||
The first change you'll notice is that our `self` type is no longer `&mut self`,
|
||||
but has changed to `Pin<&mut Self>`. We'll talk more about pinning in [a later
|
||||
but has changed to `Pin<&mut Self>`. We'll talk more about pinning in [a later
|
||||
section][pinning], but for now know that it allows us to create futures that
|
||||
are immovable. Immovable objects can store pointers between their fields,
|
||||
e.g. `struct MyFut { a: i32, ptr_to_a: *const i32 }`. Pinning is necessary
|
||||
|
|
|
@ -34,13 +34,13 @@ thread to communicate that the timer has elapsed and the future should complete.
|
|||
We'll use a shared `Arc<Mutex<..>>` value to communicate between the thread and
|
||||
the future.
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_03_timer/src/lib.rs:timer_decl}}
|
||||
```
|
||||
|
||||
Now, let's actually write the `Future` implementation!
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_03_timer/src/lib.rs:future_for_timer}}
|
||||
```
|
||||
|
||||
|
@ -55,7 +55,7 @@ being polled.
|
|||
|
||||
Finally, we need the API to actually construct the timer and start the thread:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_03_timer/src/lib.rs:timer_new}}
|
||||
```
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ futures = "0.3"
|
|||
|
||||
Next, we need the following imports at the top of `src/main.rs`:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:imports}}
|
||||
```
|
||||
|
||||
|
@ -47,7 +47,7 @@ Tasks themselves are just futures that can reschedule themselves, so we'll
|
|||
store them as a future paired with a sender that the task can use to requeue
|
||||
itself.
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:executor_decl}}
|
||||
```
|
||||
|
||||
|
@ -56,7 +56,7 @@ This method will take a future type, box it and put it in a FutureObj,
|
|||
and create a new `Arc<Task>` with it inside which can be enqueued onto the
|
||||
executor.
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:spawn_fn}}
|
||||
```
|
||||
|
||||
|
@ -70,7 +70,7 @@ the `waker_ref` or `.into_waker()` functions to turn an `Arc<impl ArcWake>`
|
|||
into a `Waker`. Let's implement `ArcWake` for our tasks to allow them to be
|
||||
turned into `Waker`s and awoken:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:arcwake_for_task}}
|
||||
```
|
||||
|
||||
|
@ -78,7 +78,7 @@ When a `Waker` is created from an `Arc<Task>`, calling `wake()` on it will
|
|||
cause a copy of the `Arc` to be sent onto the task channel. Our executor then
|
||||
needs to pick up the task and poll it. Let's implement that:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:executor_run}}
|
||||
```
|
||||
|
||||
|
@ -86,7 +86,7 @@ Congratulations! We now have a working futures executor. We can even use it
|
|||
to run `async/.await` code and custom futures, such as the `TimerFuture` we
|
||||
wrote earlier:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/02_04_executor/src/lib.rs:main}}
|
||||
```
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
In the previous section on [The `Future` Trait], we discussed this example of
|
||||
a future that performed an asynchronous read on a socket:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/02_02_future_trait/src/lib.rs:socket_read}}
|
||||
```
|
||||
|
||||
|
@ -26,9 +26,9 @@ a thread to block on multiple asynchronous IO events, returning once one of
|
|||
the events completes. In practice, these APIs usually look something like
|
||||
this:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
struct IoBlocker {
|
||||
...
|
||||
/* ... */
|
||||
}
|
||||
|
||||
struct Event {
|
||||
|
@ -41,7 +41,7 @@ struct Event {
|
|||
|
||||
impl IoBlocker {
|
||||
/// Create a new collection of asynchronous IO events to block on.
|
||||
fn new() -> Self { ... }
|
||||
fn new() -> Self { /* ... */ }
|
||||
|
||||
/// Express an interest in a particular IO event.
|
||||
fn add_io_event_interest(
|
||||
|
@ -54,10 +54,10 @@ impl IoBlocker {
|
|||
/// which an event should be triggered, paired with
|
||||
/// an ID to give to events that result from this interest.
|
||||
event: Event,
|
||||
) { ... }
|
||||
) { /* ... */ }
|
||||
|
||||
/// Block until one of the events occurs.
|
||||
fn block(&self) -> Event { ... }
|
||||
fn block(&self) -> Event { /* ... */ }
|
||||
}
|
||||
|
||||
let mut io_blocker = IoBlocker::new();
|
||||
|
@ -80,7 +80,7 @@ such as sockets that can configure callbacks to be run when a particular IO
|
|||
event occurs. In the case of our `SocketRead` example above, the
|
||||
`Socket::set_readable_callback` function might look like the following pseudocode:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
impl Socket {
|
||||
fn set_readable_callback(&self, waker: Waker) {
|
||||
// `local_executor` is a reference to the local executor.
|
||||
|
|
|
@ -12,7 +12,7 @@ code to make progress while waiting on an operation to complete.
|
|||
There are two main ways to use `async`: `async fn` and `async` blocks.
|
||||
Each returns a value that implements the `Future` trait:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/03_01_async_await/src/lib.rs:async_fn_and_block_examples}}
|
||||
```
|
||||
|
||||
|
@ -29,7 +29,7 @@ Unlike traditional functions, `async fn`s which take references or other
|
|||
non-`'static` arguments return a `Future` which is bounded by the lifetime of
|
||||
the arguments:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/03_01_async_await/src/lib.rs:lifetimes_expanded}}
|
||||
```
|
||||
|
||||
|
@ -43,7 +43,7 @@ One common workaround for turning an `async fn` with references-as-arguments
|
|||
into a `'static` future is to bundle the arguments with the call to the
|
||||
`async fn` inside an `async` block:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/03_01_async_await/src/lib.rs:static_future_with_borrow}}
|
||||
```
|
||||
|
||||
|
@ -57,7 +57,7 @@ closures. An `async move` block will take ownership of the variables it
|
|||
references, allowing it to outlive the current scope, but giving up the ability
|
||||
to share those variables with other code:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/03_01_async_await/src/lib.rs:async_move_examples}}
|
||||
```
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ Pinning makes it possible to guarantee that an object won't ever be moved.
|
|||
To understand why this is necessary, we need to remember how `async`/`.await`
|
||||
works. Consider the following code:
|
||||
|
||||
```rust
|
||||
let fut_one = ...;
|
||||
let fut_two = ...;
|
||||
```rust,edition2018,ignore
|
||||
let fut_one = /* ... */;
|
||||
let fut_two = /* ... */;
|
||||
async move {
|
||||
fut_one.await;
|
||||
fut_two.await;
|
||||
|
@ -24,7 +24,7 @@ async move {
|
|||
Under the hood, this creates an anonymous type that implements `Future`,
|
||||
providing a `poll` method that looks something like this:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
// The `Future` type generated by our `async { ... }` block
|
||||
struct AsyncFuture {
|
||||
fut_one: FutOne,
|
||||
|
@ -69,7 +69,7 @@ is able to successfully complete.
|
|||
However, what happens if we have an `async` block that uses references?
|
||||
For example:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
async {
|
||||
let mut x = [0; 128];
|
||||
let read_into_buf_fut = read_into_buf(&mut x);
|
||||
|
@ -80,7 +80,7 @@ async {
|
|||
|
||||
What struct does this compile down to?
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
struct ReadIntoBuf<'a> {
|
||||
buf: &'a mut [u8], // points to `x` below
|
||||
}
|
||||
|
@ -118,22 +118,22 @@ used as futures, and both implement `Unpin`.
|
|||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
use pin_utils::pin_mut; // `pin_utils` is a handy crate available on crates.io
|
||||
|
||||
// A function which takes a `Future` that implements `Unpin`.
|
||||
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { ... }
|
||||
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { /* ... */ }
|
||||
|
||||
let fut = async { ... };
|
||||
let fut = async { /* ... */ };
|
||||
execute_unpin_future(fut); // Error: `fut` does not implement `Unpin` trait
|
||||
|
||||
// Pinning with `Box`:
|
||||
let fut = async { ... };
|
||||
let fut = async { /* ... */ };
|
||||
let fut = Box::pin(fut);
|
||||
execute_unpin_future(fut); // OK
|
||||
|
||||
// Pinning with `pin_mut!`:
|
||||
let fut = async { ... };
|
||||
let fut = async { /* ... */ };
|
||||
pin_mut!(fut);
|
||||
execute_unpin_future(fut); // OK
|
||||
```
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
The `Stream` trait is similar to `Future` but can yield multiple values before
|
||||
completing, similar to the `Iterator` trait from the standard library:
|
||||
|
||||
```rust
|
||||
```rust,ignore
|
||||
{{#include ../../examples/05_01_streams/src/lib.rs:stream_trait}}
|
||||
```
|
||||
|
||||
|
@ -12,6 +12,6 @@ the `futures` crate. It will yield `Some(val)` every time a value is sent
|
|||
from the `Sender` end, and will yield `None` once the `Sender` has been
|
||||
dropped and all pending messages have been received:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/05_01_streams/src/lib.rs:channels}}
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ Unfortunately, `for` loops are not usable with `Stream`s, but for
|
|||
imperative-style code, `while let` and the `next`/`try_next` functions can
|
||||
be used:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/05_02_iteration_and_concurrency/src/lib.rs:nexts}}
|
||||
```
|
||||
|
||||
|
@ -19,6 +19,6 @@ writing async code in the first place. To process multiple items from a stream
|
|||
concurrently, use the `for_each_concurrent` and `try_for_each_concurrent`
|
||||
methods:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/05_02_iteration_and_concurrency/src/lib.rs:try_for_each_concurrent}}
|
||||
```
|
||||
|
|
|
@ -8,7 +8,7 @@ futures to complete while executing them all concurrently.
|
|||
When performing multiple asynchronous operations, it's tempting to simply
|
||||
`.await` them in a series:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/06_02_join/src/lib.rs:naiive}}
|
||||
```
|
||||
|
||||
|
@ -18,7 +18,7 @@ futures are ambiently run to completion, so two operations can be
|
|||
run concurrently by first calling each `async fn` to start the futures, and
|
||||
then awaiting them both:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/06_02_join/src/lib.rs:other_langs}}
|
||||
```
|
||||
|
||||
|
@ -28,7 +28,7 @@ This means that the two code snippets above will both run
|
|||
concurrently. To correctly run the two futures concurrently, use
|
||||
`futures::join!`:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/06_02_join/src/lib.rs:join}}
|
||||
```
|
||||
|
||||
|
@ -45,7 +45,7 @@ has returned an `Err`.
|
|||
Unlike `join!`, `try_join!` will complete immediately if one of the subfutures
|
||||
returns an error.
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/06_02_join/src/lib.rs:try_join}}
|
||||
```
|
||||
|
||||
|
@ -53,6 +53,6 @@ Note that the futures passed to `try_join!` must all have the same error type.
|
|||
Consider using the `.map_err(|e| ...)` and `.err_into()` functions from
|
||||
`futures::future::TryFutureExt` to consolidate the error types:
|
||||
|
||||
```rust
|
||||
```rust,edition2018,ignore
|
||||
{{#include ../../examples/06_02_join/src/lib.rs:try_join_map_err}}
|
||||
```
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
The `futures::select` macro runs multiple futures simultaneously, allowing
|
||||
the user to respond as soon as any future completes.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/06_03_select/src/lib.rs:example}}
|
||||
```
|
||||
|
||||
|
@ -27,7 +27,7 @@ if none of the other futures are ready.
|
|||
being `select`ed over have completed and will no longer make progress.
|
||||
This is often handy when looping over a `select!`.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/06_03_select/src/lib.rs:default_and_complete}}
|
||||
```
|
||||
|
||||
|
@ -58,7 +58,7 @@ which implement this trait or have been wrapped using `.fuse()`
|
|||
will yield `FusedFuture` futures from their
|
||||
`.next()` / `.try_next()` combinators.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/06_03_select/src/lib.rs:fused_stream}}
|
||||
```
|
||||
|
||||
|
@ -75,7 +75,7 @@ Note the use of the `.select_next_some()` function. This can be
|
|||
used with `select` to only run the branch for `Some(_)` values
|
||||
returned from the stream, ignoring `None`s.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/06_03_select/src/lib.rs:fuse_terminated}}
|
||||
```
|
||||
|
||||
|
@ -85,6 +85,6 @@ to the one above, but will run each copy of `run_on_new_num_fut`
|
|||
to completion, rather than aborting them when a new one is created.
|
||||
It will also print out a value returned by `run_on_new_num_fut`.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/06_03_select/src/lib.rs:futures_unordered}}
|
||||
```
|
||||
|
|
|
@ -55,7 +55,7 @@ In practice, this means that returning `Box<dyn Trait>` objects from an
|
|||
|
||||
This code will result in an error:
|
||||
|
||||
```
|
||||
```rust,edition2018,ignore
|
||||
async fn x() -> Box<dyn std::fmt::Display> {
|
||||
Box::new("foo")
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ async fn x() -> Box<dyn std::fmt::Display> {
|
|||
|
||||
This issue can be worked around by manually casting using `as`:
|
||||
|
||||
```
|
||||
```rust,edition2018
|
||||
async fn x() -> Box<dyn std::fmt::Display> {
|
||||
Box::new("foo") as Box<dyn std::fmt::Display>
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@ This can cause the compiler to fail to infer the error type of the
|
|||
|
||||
For example, this code:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# struct MyError;
|
||||
# async fn foo() -> Result<(), MyError> { Ok(()) }
|
||||
# async fn bar() -> Result<(), MyError> { Ok(()) }
|
||||
let fut = async {
|
||||
foo().await?;
|
||||
bar().await?;
|
||||
|
@ -32,7 +35,10 @@ to explicitly specify the return type of an `async` block.
|
|||
To work around this, use the "turbofish" operator to supply the success and
|
||||
error types for the `async` block:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# struct MyError;
|
||||
# async fn foo() -> Result<(), MyError> { Ok(()) }
|
||||
# async fn bar() -> Result<(), MyError> { Ok(()) }
|
||||
let fut = async {
|
||||
foo().await?;
|
||||
bar().await?;
|
||||
|
|
|
@ -19,7 +19,7 @@ struct NotSend(Rc<()>);
|
|||
Variables of type `NotSend` can briefly appear as temporaries in `async fn`s
|
||||
even when the resulting `Future` type returned by the `async fn` must be `Send`:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# use std::rc::Rc;
|
||||
# #[derive(Default)]
|
||||
# struct NotSend(Rc<()>);
|
||||
|
@ -39,14 +39,19 @@ fn main() {
|
|||
However, if we change `foo` to store `NotSend` in a variable, this example no
|
||||
longer compiles:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# use std::rc::Rc;
|
||||
# #[derive(Default)]
|
||||
# struct NotSend(Rc<()>);
|
||||
# async fn bar() {}
|
||||
async fn foo() {
|
||||
let x = NotSend::default();
|
||||
bar().await;
|
||||
}
|
||||
# fn require_send(_: impl Send) {}
|
||||
# fn main() {
|
||||
# require_send(foo());
|
||||
# }
|
||||
```
|
||||
|
||||
```
|
||||
|
@ -85,14 +90,19 @@ a block scope encapsulating any non-`Send` variables. This makes it easier
|
|||
for the compiler to tell that these variables do not live across an
|
||||
`.await` point.
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# use std::rc::Rc;
|
||||
# #[derive(Default)]
|
||||
# struct NotSend(Rc<()>);
|
||||
# async fn bar() {}
|
||||
async fn foo() {
|
||||
{
|
||||
let x = NotSend::default();
|
||||
}
|
||||
bar().await;
|
||||
}
|
||||
# fn require_send(_: impl Send) {}
|
||||
# fn main() {
|
||||
# require_send(foo());
|
||||
# }
|
||||
```
|
||||
|
|
|
@ -4,7 +4,11 @@ Internally, `async fn` creates a state machine type containing each
|
|||
sub-`Future` being `.await`ed. This makes recursive `async fn`s a little
|
||||
tricky, since the resulting state machine type has to contain itself:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
# async fn step_one() { /* ... */ }
|
||||
# async fn step_two() { /* ... */ }
|
||||
# struct StepOne;
|
||||
# struct StepTwo;
|
||||
// This function:
|
||||
async fn foo() {
|
||||
step_one().await;
|
||||
|
@ -48,6 +52,6 @@ Unfortunately, compiler limitations mean that just wrapping the calls to
|
|||
to make `recursive` into a non-`async` function which returns a `.boxed()`
|
||||
`async` block:
|
||||
|
||||
```rust
|
||||
```rust,edition2018
|
||||
{{#include ../../examples/07_05_recursion/src/lib.rs:example}}
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue