#rust #future
#Ржавчина #будущее
Вопрос:
Я учусь использовать Rust futures и нахожу это чрезвычайно запутанным. Я чувствую, что веду себя глупо, но когда будут использоваться then
, and_then
и or_else
? Какие типы возвращаемых данных ожидаются?
Пожалуйста, приведите несколько примеров различных ситуаций, которые вы ожидаете увидеть.
Ответ №1:
TL; DR: then
используется, когда вы хотите что-то сделать, независимо от того, было ли будущее успешным или нет, and_then
запускает закрытие только тогда, когда будущее было успешным, и or_else
запускает закрытие только тогда, когда будущее завершилось неудачей.
and_then
и or_else
являются прямыми аналогами методов с тем же именем на Result
.
Вашим первым шагом должно быть ознакомление с документами. Документация содержит точные сигнатуры методов (которые объясняют, какие типы он ожидает и каковы возвращаемые типы), краткое описание каждого метода, а также примеры использования.
Я извлек небольшие фрагменты документов и выделил соответствующие части.
Эта функция может быть использована для обеспечения того, чтобы вычисление выполнялось независимо от будущего завершения. Предоставленное закрытие будет произведено
Result
после завершения будущего.Возвращаемое значение замыкания должно реализовывать
IntoFuture
признак и может представлять собой еще некоторую работу, которую необходимо выполнить до завершения составленного будущего.
Эта функция может использоваться для объединения двух фьючерсов вместе и гарантировать, что окончательное будущее не будет разрешено, пока оба не завершатся. Предоставленное закрытие дает успешный результат этого будущего и возвращает другое значение, которое может быть преобразовано в будущее.
Возвращает future, который передает значение этого future, если оно выполнено успешно, а в противном случае передает ошибку в закрытие
f
и ожидает будущего, которое оно возвращает.
Тип возвращаемого значения для всех трех методов — это любой тип, который может быть преобразован в другой future.
then
: никаких дополнительных ограничений на возвращаемый тип.and_then
требуется, чтобы тип ошибки возвращаемого future соответствовал типу ошибки начального future.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(())
}
Комментарии:
1. Спасибо, что указали на документы и научили, как их использовать, чтобы иметь возможность самим находить ответы!
2. Поскольку
and_then
,then
иor_else
не фигурируют в последнем фрагменте, означает ли это, что никто никогда не использует их в асинхронном коде Rust > 1.39? (Если только не писать код асинхронной библиотеки, который в любом случае не может извлечь выгоду изasync
/await
синтаксиса?)3. @jsstuball Я не скажу, что никогда , но да, сейчас они в основном устарели. Вы также можете использовать
async
/await
синтаксис в библиотечном коде.