gpt4 book ai didi

error-handling - 使用 future 时 Either 是否有更符合人体工程学的语法?

转载 作者:行者123 更新时间:2023-11-29 08:29:08 25 4
gpt4 key购买 nike

这是使用 Tokio 运行返回 future 的函数的示例:

use futures::sync::oneshot;
use futures::Future;
use std::thread;
use std::time::Duration;
use tokio;

#[derive(Debug)]
struct MyError {
error_code: i32,
}

impl From<oneshot::Canceled> for MyError {
fn from(_: oneshot::Canceled) -> MyError {
MyError { error_code: 1 }
}
}

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
let (sx, rx) = oneshot::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(100));
sx.send(100).unwrap();
});
return rx.map_err(|e| MyError::from(e));
}

fn main() {
tokio::run(deferred_task().then(|r| {
println!("{:?}", r);
Ok(())
}));
}

但是,当所讨论的函数(即 deferred_task)非常重要时,我编写代码时会变得复杂得多,因为 ? 操作不会t 似乎很容易与返回 future 混在一起:

fn send_promise_to_worker(sx: oneshot::Sender<i32>) -> Result<(), ()> {
// Send the oneshot somewhere in a way that might fail, eg. over a channel
thread::spawn(move || {
thread::sleep(Duration::from_millis(100));
sx.send(100).unwrap();
});
Ok(())
}

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
let (sx, rx) = oneshot::channel();
send_promise_to_worker(sx)?; // <-------- Can't do this, because the return is not a result
return rx.map_err(|e| MyError::from(e));
}

一个Future 一个Result,用result包裹它是没有意义的,它破坏了impl Future 返回类型。

取而代之的是一个深度嵌套的链:

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
let (sx, rx) = oneshot::channel();
match query_data() {
Ok(_i) => match send_promise_to_worker(sx) {
Ok(_) => Either::A(rx.map_err(|e| MyError::from(e))),
Err(_e) => Either::B(futures::failed(MyError { error_code: 2 })),
},
Err(_) => Either::B(futures::failed(MyError { error_code: 2 })),
}
}

full code

结果越多,嵌套越深; ? 运算符通常解决的问题。

我错过了什么吗?是否有一些语法糖可以使这更容易?

最佳答案

我怎么看不出来async/await语法将明确帮助您 Either .最终,您仍然需要返回一个具体类型,这就是 Either提供。 async/await将减少对 Future::map 等组合器的需求或 Future::and_then然而。

另见:


也就是说,您不需要使用 Either在这里。

您有连续的 Result - 返回函数,所以你可以借用 JavaScript 的技巧并使用 IIFE使用 ?运算符(operator)。然后,我们可以“提升”组合 Result进入 future 并将其与接收者的 future 链接起来:

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
let (tx, rx) = oneshot::channel();

let x = (|| {
let _i = query_data().map_err(|_| MyError { error_code: 1 })?;
send_promise_to_worker(tx).map_err(|_| MyError { error_code: 2 })?;
Ok(())
})();

future::result(x).and_then(|()| rx.map_err(MyError::from))
}

在未来,IIFE 可以用 try 代替 block ,据我了解。

你也可以走另一条路,把一切都变成 future :

fn deferred_task() -> impl Future<Item = i32, Error = MyError> {
let (tx, rx) = oneshot::channel();

query_data()
.map_err(|_| MyError { error_code: 1 })
.into_future()
.and_then(|_i| {
send_promise_to_worker(tx)
.map_err(|_| MyError { error_code: 2 })
.into_future()
})
.and_then(|_| rx.map_err(MyError::from))
}

得到async的帮助/await语法:

async fn deferred_task() -> Result<i32, MyError> {
let (tx, rx) = oneshot::channel();

query_data().map_err(|_| MyError { error_code: 1 })?;

send_promise_to_worker(tx).map_err(|_| MyError { error_code: 2 })?;

let v = await! { rx }?;

Ok(v)
}

我还看到了构建 Either 的改进语法通过添加 leftright Future 的方法特点:

foo.left();
// vs
Either::left(foo);

但是,这不会出现在任何当前的实现中。

A Future is a Result

不,不是。

有两个相关的Future让我们谈谈:

值得注意的是,Future::poll返回一个可以处于两种状态的类型:

  • 完成
  • 不完整

在 futures crate 中,“成功”和“失败”与“完成”相关联,而在标准库中则不是。在箱子里,Result工具 IntoFuture , 在标准库中你可以使用 future::ready .这两个都允许转换 Result进入 future ,但这并不意味着Result 一个 future ,只不过是说 Vec<u8>是一个迭代器,即使它可以转换为一个迭代器。

有可能 ?运算符(由 Try 特性提供支持),将得到增强以自动从 Result 转换到特定类型的 Future ,或者那个 Result甚至会实现 Future直接,但我没有听说过任何此类计划。

关于error-handling - 使用 future 时 Either 是否有更符合人体工程学的语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55155493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com