[英]How can I alter the behavior of a function based on the return type of a closure passed as an argument?
我有一个 function 返回咖喱 function 的结果:
async fn runit<F, Fut, Ret>(cb: F) -> Result<Ret, MyError>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Ret>,
{
Ok(cb().await)
}
有时F
可能会返回一个Result<Ret, MyError>
,要求调用者将返回的值解包两次。 有没有一种方法可以让 function 自动检测F
是否已经返回正确的类型并避免调用Ok
?
您也许可以将 trait 与Result
和其他类型的单独一揽子实现一起使用。 就像是:
pub trait IntoResult<T, E> {
fn into_result(self) -> Result<T, E>;
}
impl<T, E> IntoResult<T, E> for Result<T, E> {
fn into_result(self) -> Result<T, E> {
self
}
}
impl<T, E> IntoResult<T, E> for T {
fn into_result(self) -> Result<T, E> {
Ok(self)
}
}
然后你可以实现runit
来调用into_result()
:
async fn runit<F, Fut, Ret, RawRet>(cb: F) -> Result<Ret, MyError>
where
F: FnOnce() -> Fut,
Fut: Future<Output = RawRet>,
RawRet: IntoResult<Ret, MyError>,
{
cb().await.into_result()
}
现在 Rust 将能够推断出满足IntoResult
特征的Ret
,有效地消除了内部Result
:
// one unwrap needed for Result<usize, MyError>
let _x: usize = runit(|| async { 1 }).await.unwrap();
// two unwraps needed because closure returns Result whose error is not MyError
let _y: usize = runit(|| async { Ok::<_, std::io::Error>(1usize) })
.await
.unwrap()
.unwrap();
// one unwrap enough because closure returns Result<usize, MyError>
let _z: usize = runit(|| async { Ok::<_, MyError>(1usize) }).await.unwrap();
在生产中使用它之前,我建议对这种“聪明”非常小心。 虽然它在工作时看起来非常好,但它会使函数的签名复杂化,有时它可能需要类型提示,否则就不需要了。 使用类似anyhow::Error
的方法将不兼容错误的结果合并为一个结果通常更简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.