Rust期货中的`then`,`and_then`和`or_else`有什么区别?

Ena*_*ain 2 future rust

我正在学习使用Rust期货,并且感到非常困惑。我觉得我太傻了,但是当会thenand_thenor_else使用吗?期望什么返回类型?

请提供一些您希望看到的不同情况的示例。

She*_*ter 8

TL; DR:then在无论将来是否成功都想做某事时使用,and_then仅在将来成功or_else时才运行闭包,而在将来失败时才运行闭包。

and_then并且or_else是与上同名方法的直接类似物Result


您的第一步应该是阅读文档。该文档包含确切的方法签名(说明了期望的类型和返回的类型),描述每个方法的散文以及示例用法。

我提取了文档的小片段,并强调了相关部分。

Future::then

无论未来如何结束,此功能都可用于确保计算运行Result一旦将来完成,将提供所提供的关闭 。

闭包的返回值必须实现该IntoFuture特征,并且可以表示在完成组成的将来之前要完成的更多工作。

Future::and_then

此功能可用于将两个期货链接在一起,并确保直到两个期货都完成才解决最终的期货。提供的闭包产生了该未来的成功结果,并返回了另一个可以转换为未来的值。

Future::or_else

如果成功,则返回传递该期货值的期货,否则将错误传递给闭包,f并等待其返回。

这三种方法的返回类型都是可以转换为另一个未来的任何类型。

  • then:对返回类型没有其他限制。
  • and_then 要求返回的期货的错误类型与起始期货的错误类型匹配。
  • or_else 要求返回的未来的成功类型与开始的未来的成功类型匹配。

use futures::{future, Future}; // 0.1.25

struct Error;

fn download_from_server(server: u8) -> impl Future<Item = Vec<u8>, Error = Error> {
    /* ... */
}

fn upload_to_server(data: Vec<u8>) -> impl Future<Item = usize, Error = Error> {
    /* ... */
}

// Uses `or_else` to do work on failure
fn download() -> impl Future<Item = Vec<u8>, Error = Error> {
    download_from_server(0)
        .or_else(|_| download_from_server(1))
        .or_else(|_| download_from_server(2))
}

// Uses `and_then` to do work on success
fn reupload() -> impl Future<Item = usize, Error = Error> {
    download().and_then(|data| upload_to_server(data))
}

// Uses `then` to always do work
fn do_things() -> impl Future<Item = (), Error = ()> {
    reupload().then(|r| {
        match r {
            Ok(size) => println!("Uploaded {} bytes", size),
            Err(_) => println!("Got an error"),
        };
        Ok(())
    })
}
Run Code Online (Sandbox Code Playgroud)

在Rust 1.39中稳定的async/ await语法简化了某些情况:

// Equivalent to `or_else`
async fn download() -> Result<Vec<u8>, Error> {
    match download_from_server(0).await {
        Ok(v) => Ok(v),
        Err(_) => match download_from_server(1).await {
            Ok(v) => Ok(v),
            Err(_) => download_from_server(2).await,
        },
    }
}

// Equivalent to `and_then`
async fn reupload() -> Result<usize, Error> {
    let data = download().await?;
    upload_to_server(data).await
}

// Equivalent to `then`
async fn do_things() -> Result<(), ()> {
    match reupload().await {
        Ok(size) => println!("Uploaded {} bytes", size),
        Err(_) => println!("Got an error"),
    }
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您指出这些文档并教导如何使用它们以便我们自己找到答案! (2认同)