rust - 如何根据作为参数传递的闭包的返回类型来改变函数的行为?
问题描述
我有一个返回柯里化函数结果的函数:
async fn runit<F, Fut, Ret>(cb: F) -> Result<Ret, MyError>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Ret>,
{
Ok(cb().await)
}
有时F
可能会返回 a Result<Ret, MyError>
,要求调用者将返回的值解开两次。有没有一种方法可以让函数自动检测是否F
已经返回正确的类型并避免调用Ok
?
解决方案
您可能可以使用具有单独的毯子实现的特征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 将能够推断出Ret
满足IntoResult
trait,有效地消除了 inner 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
使用诸如将不兼容错误的结果合并为一个结果之类的方法通常更简单。
推荐阅读
- python - 如何在for循环中将列表数字组合成总和?
- python - 根据行值更改过滤分组数据框
- r - 多类 kNN 中的 ROC
- vue.js - PrimeVue 数据表不显示
- javascript - 仅在 Firefox 中,“location.href = ..”重定向后未到达或停止警报框
- c - 为什么我的 scanf 函数在我的代码中不起作用并被忽略?
- javascript - Npm 使用正确的 package.json 共享 node_modules
- javascript - 获取 UTC 日期范围
- node.js - 为什么 resolve("./../....") 和 resolve("foo") 有区别
- python - Excel在Openpyxl生成的工作簿中添加@符号