We saw a few of the most important combinators in the futures and streams overviews. Here we’ll take a look at a few more. It’s also worth spending some time with the trait documentation to familiarize yourself with the full range of combinators available (cheatsheet).
Some concrete futures and streams
Any value can be turned into an immediately complete future. There are a few
functions in the
future module for creating such a future:
ok, which is analogous to
Result::Ok: it treats the value you give it as an immediately successful future.
err, which is analogous to
Result::Err: it treats the value you give it as an immediately failed future.
result, which lifts a result to an immediately-complete future.
For streams, there are a few equivalents of an “immediately ready” stream:
iter, which creates a stream that yields the same items as the underlying iterator. The iterator produces
Resultvalues, and the first error terminates the stream with that error.
once, which creates a single-element stream from a
In addition to these constructors, there’s also a function,
allows you to construct a future given a closure that will produce that future
later, on demand.
A crucial API to know about is the
IntoFuture trait, which is a trait for
values that can be converted into futures. Most APIs that you think of as taking
futures actually work with this trait instead. The key reason: the trait is
Result, allowing you to return
Result values in many places
that futures are expected.
Sink traits all come equipped
with a broad range of “adapter” methods. These methods all consume the receiving
object and return a new, wrapped one. For futures, you can use adapters to:
- Change the type of a future (
- Run another future after one has completed (
- Figure out which of two futures resolves first (
- Wait for two futures to both complete (
- Convert to a trait object (
- Convert unwinding into errors (
For streams, there are a large set of adapters, including:
- Many in common with
skipand so on. Note that
collectproduce futures, and hence their result is computed asynchronously.
- Adapters for sequencing with futures (
- Additional adapters for combining streams (
Sink trait currently has fewer adapters
Finally, an object that is both a stream and a sink can be broken into separate
stream and sink objects using the
All adapters are zero-cost, meaning that no memory is allocated internally and the implementation will optimize to what you would have otherwise written by hand.
Futures, streams and sinks all treat error handling as a core concern: they are all equipped with an associated error type, and the various adapter methods interpret errors in sensible ways. For example:
The sequencing combinators
map_errall chain errors similarly to the
Resulttype in the standard library. So, for example, if you chain futures using
and_thenand the first future fails with an error, the chained future is never run.
joinalso deal with errors. For
select, the first future to complete in any way yields an answer, propagating the error, but also giving access to the other future should you want to keep working with it. For
join, if any future produces an error, the entire join produces that error.
By default, futures don’t have any special handling for panics. In most cases,
though, futures are ultimately run as tasks within a thread pool, where you’ll
want to catch any panic they produce and propagate that elsewhere. The
catch_unwind adapter can be used to reify a panic into a
taking down the worker thread.