rust - Rust:如何定义一个可以返回任一结果的闭包或结果>
问题描述
我正在尝试定义一个通用闭包,以便它可以返回Result
包含任何类型错误的 a ,特别是在 a 中的特定错误或通用错误Box
。我有一个游乐场示例,说明了我在这里尝试做的事情,但这是一个缩短的版本:
fn try_with_context<T, F: FnOnce() -> Result<T, Box<dyn Error>>>(
context: &str,
block: F,
) -> Result<T, Box<dyn Error>> {
match block() {
Ok(v) => Ok(v),
Err(e) => Err(e),
}
}
我想支持给定block
的能够返回 aResult<T, MyError>
或Result<T, Box<dyn Error>>
,但当前返回Err(MyError)
失败:
fn error_func() -> Result<u8, MyError> {
Err(MyError {})
}
fn do_something() {
// This won't work: Expected Box, found struct MyError
try_with_context("something", || error_func());
}
现在,有几个解决方法可以使这项工作:
try_with_context("something", || Ok(error_func()));
或者
try_with_context("something", || error_func().map_err(Into::into));
两者都修复它,但我希望有一种方法来定义它,这样这些变通方法都不是必需的(该try_with_context
方法是库的一部分,我发现用户必须使用这些方法是不直观的,所以我我希望避免需要它)。
我已经尝试引入另一种泛型来尝试解决它:
fn try_with_context_2<T, U, F: FnOnce() -> Result<T, U>>(
context: &str,
block: F,
) -> Result<T, Box<dyn Error>>
where
U: Error + 'static,
{
match block() {
Ok(v) => Ok(v),
Err(e) => Err(e.into()),
}
}
但不幸的是,这只是扭转了这里的问题:现在Err(MyError{})
版本很好,但抱怨返回的版本Box<dyn Error>
。
第三个版本确实解决了这两个简单的用例:
fn try_with_context_3<T, U, F: FnOnce() -> Result<T, U>>(
context: &str,
block: F,
) -> Result<T, Box<dyn Error>>
where
U: Into<Box<dyn Error>>,
{
match block() {
Ok(v) => Ok(v),
Err(e) => Err(e.into()),
}
}
但是当我尝试更复杂的版本时block
,错误会以奇怪的方式出现,例如:
try_with_context("something", || {
other_error_func()?;
error_func()?
});
抱怨'?' couldn't convert the error to 'MyError'
,但是:
try_with_context("something", || {
error_func()?;
other_error_func()
});
很好。
有没有一种好的方法来定义可以在没有变通方法的情况下处理所有这些情况的闭包?
编辑:在阅读@isaactfa 的答案后,我对此进行了更多思考,并意识到它确实归结为一些基本的东西:我正在有效地尝试定义一个可以返回实现的特定类型或Error
a 的方法Box<dyn Error>
,所以我需要泛型足够广泛以允许这两种可能性中的任何一种,但这意味着(至少在我尝试过的每次迭代中)如果该函数的显式返回返回一个特定的实现类型Error
,那么编译器将尝试并强制任何更早的?
样式返回到该特定错误类型,这不起作用。我仍然很想听听是否有一种聪明的方法来解决这个问题,但与此同时,我将使用我上面提到的一种解决方法(并且可能会定义一些辅助函数包装器.map_err(Into::into)
以使其更符合人体工程学。
解决方案
问题是在
try_with_context_3("something", || {
other_error_func()?;
error_func()
});
你正在返回 aResult<_, MyError>
所以 Rust 期望它是返回类型。?
操作员足够聪明,可以尝试将它遇到的所有其他错误类型转换为实际返回的错误类型。这实际上只给您留下两个选择:强制闭包始终返回 a Box<dyn Error + 'static>
,并使其符合人体工程学,可能通过为您的自定义错误类型提供适当的构造函数,或者提供一种?
将 a 转换Box<dyn Error + 'static>
为 a 的方法MyError
:
impl From<Box<dyn Error + 'static>> for MyError {
fn from(_t: Box<dyn Error + 'static>) -> Self {
MyError
}
}
有了它,这将编译:
fn do_something() {
try_with_context_3("something", || error_func());
try_with_context_3("something", || other_error_func());
try_with_context_3("something", || {
other_error_func()?;
error_func()
});
try_with_context_3("something", || {
error_func()?;
other_error_func()
});
}
推荐阅读
- azure - 为什么日志分析查询没有返回我使用编码(REST API)将 VM 与工作区集成的结果?
- javascript - 使用 Bootstrap 4 在单行上创建动态下拉项
- php - 未定义的属性:App\Controllers\Courtyard::$uri
- string - Dart/Flutter Map 有空奇怪的空键,导致一个值
- node.js - Node JS 异步概念
- html2canvas - 无法使用 pdfmaker 向 pdf 添加多个页面
- windows - 用于获取已闲置 90 天或更长时间的用户帐户的 Windows 命令
- python-3.x - wait_for reaction_add 总是超时
- amazon-web-services - 如何描述 cloudformation 跨帐户堆栈信息/名称/详细信息
- laravel - 在没有 laravel 的情况下对录制的后备支持