Tokio select 宏观条件和手臂评估

Tokio select macro conditions and arm evaluation

我有一段代码需要从多个TcpStream中读取。其中一个 TcpStream 将永远存在,但另一个可能存在也可能不存在。

我之前写过代码并(天真地)在 tokio select 宏上使用了条件。不幸的是,我很快了解到宏将首先评估手臂(以获得未来),然后才会检查条件,并根据该条件启动未来或跳过它。

因此,当我 运行 这段代码时,我将得到: thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:16:35

use tokio::io::AsyncReadExt;
use tokio::net::TcpStream;

#[tokio::main]
async fn main() {
    let mut stream1 : TcpStream = TcpStream::connect("info.cern.ch:80").await.unwrap();
    let mut stream2 : Option<TcpStream> = None;
    let mut buf = vec![0_u8; 1024];
    let mut buf2 = vec![0_u8; 1024];
    
    tokio::select! {
        result = stream1.read(&mut buf) => {
            // do something here
        }
        
        result = stream2.as_mut().unwrap().read(&mut buf2), if stream2.is_some() => {
            // do somethihng here
        }
    }
    
}

我的问题是如何处理?

我偶然发现了以下想法,但我对其中任何一个都不满意

我正在寻找可以让我保留这个 select 的方法!在选项

您可以将 optiona 流的处理包装到另一个未来,也许会返回一个自定义错误。然后在成功读取时进行模式匹配:

use tokio::io::AsyncReadExt;
use tokio::net::TcpStream;
use std::io::{Error, ErrorKind};

#[tokio::main]
async fn main() {
    let mut stream1 : TcpStream = TcpStream::connect("info.cern.ch:80").await.unwrap();
    let mut stream2 : Option<TcpStream> = None;
    let mut buf = vec![0_u8; 1024];
    let mut buf2 = vec![0_u8; 1024];
    
    let read2 = async move {
        match stream2 {
            Some(mut stream) => stream.read(&mut buf2).await,
            _ => Err(Error::new(ErrorKind::Other, "No available stream")),
        }
    };
    
    tokio::select! {
        result = stream1.read(&mut buf) => {
            // do something here
        }
        
        Ok(result) = read2 => {
            // do somethihng here
        }
    }
    
}

Playground

如果您不喜欢自定义错误,您可以在 Option<Result> 中重新包装所有内容并匹配所有内容:

...
    let read2 = async move {
        match stream2 {
            Some(mut stream) => Some(stream.read(&mut buf2).await),
            None => None,
        }
    };
    
    tokio::select! {
        result = stream1.read(&mut buf) => {
            // do something here
        }
        
        Some(result) = read2 => {
            // do somethihng here
        }
    }
...

Playground