如何根据作为参数传递的闭包的返回类型来更改函数的行为



我有一个函数,它返回当前函数的结果:

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>,要求调用者打开返回值两次。有没有一种方法可以让函数自动检测F是否已经返回了正确的类型,并避免调用Ok

您可能能够将trait与Result和其他类型的单独blanket实现一起使用。类似于:

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的东西将不兼容错误的结果合并为一个结果通常更简单。

相关内容

  • 没有找到相关文章