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

25

我正在学习使用 Rust futures,但是我发现它非常令人困惑。我感觉自己很傻,但是在什么情况下应该使用 thenand_thenor_else 呢?它们期望的返回类型是什么?

请提供一些不同情况下你预计会用到这些内容的例子。

1个回答

39

简而言之:当你希望无论未来是否成功都要执行某些操作时,使用then;当未来成功时才执行某个闭包时,使用and_then;当未来失败时才执行某个闭包时,使用or_else

and_thenor_else直接对应于Result上同名方法。


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

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

FutureExt::then:

此函数可用于确保计算无论如何都会运行,提供的闭包将在未来完成后产生一个Result

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

FutureExt::and_then:

这个函数可以用来将两个 futures 链接在一起,并确保直到两者都完成后才解决最终的 future。提供的闭包会产生此 future 的成功结果,并返回另一个可以转换为 future 的值。 FutureExt::or_else 返回一个 future,如果成功,则传递此 future 的值,否则将错误传递给闭包 f 并等待它返回的 future。
所有三种方法的返回类型都是可以转换为另一个 future 的任何类型。
- then:对返回类型没有额外限制。 - and_then 要求返回的 future 的错误类型与起始 future 的错误类型匹配。 - or_else 要求返回的 future 的成功类型与起始 future 的成功类型匹配。
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(())
    })
}

在 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(())
}

2
感谢您指导如何使用文档自己找到答案! - LittleTiger
由于and_thenthenor_else在最终代码片段中没有出现,这是否意味着在1.39以上的异步Rust代码中从不使用它们?(除非编写无法从async/await语法中受益的异步库代码?) - jsstuball
1
@jsstuball 我不会说“永远”,但是现在它们大多数都已经过时了。您也可以在库代码中使用 async / await 语法。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接