Pattern matching

Recall that the select! macro branch syntax was defined as:

  1. <pattern> = <async expression> => <handler>,

So far, we have only used variable bindings for <pattern>. However, any Rust pattern can be used. For example, say we are receiving from multiple MPSC channels, we might do something like this:

  1. use tokio::sync::mpsc;
  2. #[tokio::main]
  3. async fn main() {
  4. let (mut tx1, mut rx1) = mpsc::channel(128);
  5. let (mut tx2, mut rx2) = mpsc::channel(128);
  6. tokio::spawn(async move {
  7. // Do something w/ `tx1` and `tx2`
  8. });
  9. tokio::select! {
  10. Some(v) = rx1.recv() => {
  11. println!("Got {:?} from rx1", v);
  12. }
  13. Some(v) = rx2.recv() => {
  14. println!("Got {:?} from rx2", v);
  15. }
  16. else => {
  17. println!("Both channels closed");
  18. }
  19. }
  20. }

In this example, the select! expression waits on receiving a value from rx1 and rx2. If a channel closes, recv() returns None. This does not match the pattern and the branch is disabled. The select! expression will continue waiting on the remaining branches.

Notice that this select! expression includes an else branch. The select! expression must evaluate to a value. When using pattern matching, it is possible that none of the branches match their associated patterns. If this happens, the else branch is evaluated.