TL;DR: then
используется, когда вы хотите что-то сделать независимо от того, было ли будущее успешным или нет, and_then
запускает закрытие только тогда, когда будущее успешно, а or_else
запускает закрытие, только когда будущее не удалось.
and_then
и or_else
— прямые аналоги одноименных методов на Result
.
Ваш первый шаг должен состоять в том, чтобы прочитать документы. Документация содержит точные сигнатуры методов (которые объясняют, какие типы он ожидает и какие типы возвращаемых данных), подробное описание каждого метода, а также примеры использования.
Я извлек небольшие фрагменты документов и подчеркнул соответствующие части.
This function can be used to ensure a computation runs regardless of the conclusion of the future. The closure provided will be yielded a
Result
once the future is complete.The returned value of the closure must implement the
IntoFuture
trait and can represent some more work to be done before the composed future is finished.
This function can be used to chain two futures together and ensure that the final future isn't resolved until both have finished. The closure provided is yielded the successful result of this future and returns another value which can be converted into a future.
Return a future that passes along this future's value if it succeeds, and otherwise passes the error to the closure
f
and waits for the future it returns.
Тип возвращаемого значения для всех трех методов — любой тип, который можно преобразовать в другое будущее.
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(())
})
}
Некоторые случаи упрощаются синтаксисом async
/await
, стабилизированным в Rust 1.39:
// 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(())
}
Спасибо, что указали на документы и научили их использовать, чтобы иметь возможность самостоятельно находить ответы!