error-handling - 如何使用问号运算符来处理 Tokio 期货中的错误?
问题描述
我有一个客户处理Future
一些事情。是否可以impl Future<Item = (), Error = io::Error>
用作返回类型并进行更好的错误处理?
pub fn handle_client(client: Client) -> impl Future<Item = (), Error = io::Error> {
let magic = client.header.magic;
let stream_client = TcpStream::connect(&client.addr).and_then(|stream| {
let addr: Vec<u8> = serialize_addr(stream.local_addr()?, magic)?;
write_all(stream, addr).then(|result| {
// some code
Ok(())
})
});
stream_client
}
我无法io::Error
通过所有嵌套的闭包/期货来保持类型。编译器抛出错误
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/client.rs:134:29
|
134 | let addr: Vec<u8> = serialize_addr(stream.local_addr()?, magic)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `futures::future::then::Then<tokio_io::io::write_all::WriteAll<tokio_tcp::stream::TcpStream, std::vec::Vec<u8>>, std::result::Result<(), std::io::Error>, [closure@src/client.rs:135:38: 138:10]>`
|
= help: the trait `std::ops::Try` is not implemented for `futures::future::then::Then<tokio_io::io::write_all::WriteAll<tokio_tcp::stream::TcpStream, std::vec::Vec<u8>>, std::result::Result<(), std::io::Error>, [closure@src/client.rs:135:38: 138:10]>`
= note: required by `std::ops::Try::from_error`
我进行了链接 map/and_then 错误处理,但问题是我不知道如何TcpStream
进入最终.then
闭包。我发现的唯一地方TcpStream
是在 WriteAll 结构中,但它是私有的。此外, write_all 消耗流
use futures::Future;
use std::{io, net::SocketAddr};
use tokio::{
io::{write_all, AsyncRead, AsyncWrite},
net::TcpStream,
};
type Error = Box<dyn std::error::Error>;
fn serialize_addr(addr: SocketAddr) -> Result<Vec<u8>, Error> {
Ok(vec![])
}
fn handle_client(addr: &SocketAddr) -> impl Future<Item = (), Error = Error> {
TcpStream::connect(addr)
.map_err(Into::into)
.and_then(|stream| stream.local_addr().map(|stream_addr| (stream, stream_addr)))
.map_err(Into::into)
.and_then(|(stream, stream_addr)| serialize_addr(stream_addr).map(|info| (stream, info)))
.map(|(stream, info)| write_all(stream, info))
.then(|result| {
let result = result.unwrap();
let stream = match result.state {
Writing { a } => a,
_ => panic!("cannot get stream"),
};
// some code
Ok(())
})
}
fn main() {
let addr = "127.0.0.1:8900".parse().unwrap();
handle_client(&addr);
}
解决方案
TL;DR:您不使用?
运算符。
由于您没有提供一个,这里是您的问题的MCVE。请注意,我们不知道您的serialize_addr
函数的错误类型是什么,所以我不得不选择一些东西:
use futures::Future;
use std::{io, net::SocketAddr};
use tokio::{io::write_all, net::TcpStream};
fn serialize_addr() -> Result<Vec<u8>, Box<dyn std::error::Error>> {
Ok(vec![])
}
pub fn handle_client(addr: &SocketAddr) -> impl Future<Item = (), Error = io::Error> {
TcpStream::connect(addr).and_then(|stream| {
let addr = serialize_addr()?;
write_all(stream, addr).then(|_result| Ok(()))
})
}
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/lib.rs:11:20
|
11 | let addr = serialize_addr()?;
| ^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `futures::future::then::Then<tokio_io::io::write_all::WriteAll<tokio_tcp::stream::TcpStream, std::vec::Vec<u8>>, std::result::Result<(), std::io::Error>, [closure@src/lib.rs:12:38: 14:10]>`
|
= help: the trait `std::ops::Try` is not implemented for `futures::future::then::Then<tokio_io::io::write_all::WriteAll<tokio_tcp::stream::TcpStream, std::vec::Vec<u8>>, std::result::Result<(), std::io::Error>, [closure@src/lib.rs:12:38: 14:10]>`
= note: required by `std::ops::Try::from_error`
正如错误消息所述:
运算符
?
只能用于返回Result
或Option
(或实现的另一种类型std::ops::Try
)的函数中
和
不能
?
在返回的函数中使用运算符Then<WriteAll<TcpStream, Vec<u8>>, Result<(), io::Error>, [closure]>
Result
相反,利用可以被视为未来的事实,让它参与到功能链中。
此外,就像 Rust 中的其他任何地方一样,您需要有一个统一的错误类型。为了简单起见,我选择Box<dyn Error>
了。这可以使用map_err
和Into::into
use futures::Future;
use std::net::SocketAddr;
use tokio::{io::write_all, net::TcpStream};
type Error = Box<dyn std::error::Error>;
fn serialize_addr() -> Result<Vec<u8>, Error> {
Ok(vec![])
}
pub fn handle_client(addr: &SocketAddr) -> impl Future<Item = (), Error = Error> {
TcpStream::connect(addr)
.map_err(Into::into)
.and_then(|stream| serialize_addr().map(|addr| (stream, addr)))
.and_then(|(stream, addr)| write_all(stream, addr).map_err(Into::into))
.then(|_result| Ok(()))
}
将来,async
/await
语法将使这更容易理解。
推荐阅读
- bitmap - Zebra 打印机 (P430i):如何使用 EPCL 打印位图
- html - 我可以在带有输入的标签内选择 ::after 吗?
- python - 预处理文本以输入在 imdb 数据集上训练的模型
- wolfram-mathematica - 求解 6 个不工作的变量的 6 个非线性方程
- python - python - 如何定义一个创建与python相互嵌入的for循环的函数?
- python - 如何使用从 cvxopt.solvers 获得的参数绘制非线性决策边界?
- perl - Perl 在第二个元素后加入数组
- python - 用于查找子字符串的正则表达式
- angular - Angular 无法使用可观察的服务调用方法
- python - ttk Progressbar 使用 grid vs pack 的问题