Error handling 使用futures时是否有更符合人体工程学的语法?
下面是一个使用Tokio运行函数返回未来的示例:Error handling 使用futures时是否有更符合人体工程学的语法?,error-handling,syntax,rust,future,Error Handling,Syntax,Rust,Future,下面是一个使用Tokio运行函数返回未来的示例: 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(_:
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(())
}));
}
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));
}
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))
}
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 })),
}
}
fn延迟的任务()->impl Future{
let(sx,rx)=oneshot::channel();
匹配查询_数据(){
Ok(_i)=>匹配发送承诺给员工(sx){
Ok(|)=>A(rx.map_err(| e | MyError::from(e)),
Err(_e)=>B(futures::failed(MyError{error_code:2})),
},
Err()=>B(futures::failed(MyError{error_code:2})),
}
}
结果越多,嵌套越深;正是?
运算符正常解决的问题
我错过什么了吗?是否有一些语法糖可以让这更容易
是否有一些语法糖可以让这更容易
是的,它被称为async/await,但它还没有准备好广泛使用。它只在夜间受支持,它使用了与Tokio稍有不同的futures版本,Tokio只通过一个互操作库支持该版本,这会导致额外的语法开销,而且整个过程的文档仍然不完整
以下是一些相关链接:
我看不出
async
/wait
语法在或方面有什么绝对的帮助。最终,您仍然需要返回一个具体类型,这就是或提供的async
/await
将减少对组合器的需求,例如Future::map
或Future::and\u then
另见:
也就是说,这里也不需要使用
您有连续的Result
-返回函数,因此您可以借用JavaScript的技巧,使用?
操作符。然后,我们可以将组合的结果
提升到未来,并将其与来自接收器的未来链接起来:
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))
}
这将有助于使用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)
}
但是,这在当前的任何实现中都没有出现
未来
是一个结果
不,不是
有两个相关的未来
可以讨论:
值得注意的是,Future::poll
返回的类型可以处于两种状态:
- 完整的
- 不完整
在futures板条箱中,“成功”和“失败”与“完成”关联,而在标准库中则不是。在板条箱中,Result
实现,在标准库中可以使用。这两种方法都允许将结果
转换为未来,但这并不意味着结果
是未来,只不过说Vec
是迭代器,即使它可以转换为迭代器
?
操作符(由Try
特性提供动力)可能会被增强,以自动从结果
转换为特定类型的未来
,或者结果
甚至会直接实现未来
,但我还没有听说过这样的计划
foo.left();
// vs
Either::left(foo);