我有一个函数float_or_err(i)
,它接受一个整数并返回一个浮点数或一个错误。我想写一个函数,它接受一个整数数组,并返回float_or_err(i)
最大的那个,或者如果float_or_err()
在任何i
上出错,则传播错误。
现在,我已经阅读了Using max_by_key on a vector of floats [duplicate],我明白了为什么Rust没有在浮点数上实现全排序,我决定使用ordered_float
而不是f64
来对float_or_err()
的结果施加全排序。
然而,这个问题并没有解决.max_by_key()
的参数是一个返回Result<OrderedFloat<f64>, _>
的闭包的情况,如下面的例子所示:
use ordered_float::OrderedFloat;
fn main() {}
enum ErrorKind {
ValidationError
}
// Function of `i` that normally returns an f64 but sometimes has an error
fn float_or_err(i: &isize) -> Result<OrderedFloat<f64>, ErrorKind> {
if i % 5 == 0 {
return Err(ErrorKind::ValidationError);
}
else {
return Ok(OrderedFloat(3.14));
}
}
// Given a vec of integers `i`, find the one for which `float_or_err(i)` is
// largest. If any of those integers `i` yields an error in `float_or_err(i)`,
// return the error.
fn max_by_float_or_err(v: Vec<isize>) -> Option<&isize> {
return v.iter().max_by_key(|i| float_or_err(i));
}
编译器不接受倒数第二行,因为
the trait bound `ErrorKind: Ord` is not satisfied
the trait `Ord` is implemented for `Result<T, E>`
好吧,看起来我需要做一些
impl Ord for Result<OrderedFloat<f64>, ErrorKind> {
// ...
}
(我首先通过浮动排序,然后使用ErrorKind作为决胜局。)
但是编译器不允许我为一个不是我创建的类型实现Ord
:
`Result` is not defined in the current craterustcE0117
main.rs(9, 1): original diagnostic
only traits defined in the current crate can be implemented for types defined outside of the crate
实际上,我的第一直觉是这样写的:
fn argmax_by_float_or_err(v: Vec<isize>) -> Option<&isize> {
return v.iter().max_by_key(|i| float_or_err(i)?);
}
但是这也不能编译,因为你不能在闭包中使用问号操作符。我读过Alternatives for using the question mark operator inside a map function closure,其中建议的解决方案是将问号移动到链的末尾,但该解决方案特定于所讨论的函数,其中reduce op是.sum()
而不是.max_by_key()
,并且.sum()
是针对Result的本地实现。.max_by_key()
(以及许多其他reduce操作)的情况并非如此。
- 在上面定义的
max_by_float_or_err()
函数的上下文中,如何从float_or_err()
传播错误? - 我正在寻找一个使用
.max_by_key()
(或至少另一个reduce操作)的解决方案,而不是将主体重写为for循环。 - 编辑:* 我也读了How do I implement a trait I don't own for a type I don't own?,它建议类似于:
struct MyResult(Result<OrderedFloat<f64>, ErrorKind>);
impl Ord for MyResult {
// ...
}
这个解决方案并不令人满意,因为MyResult
的示例似乎没有继承与普通Result
s相关联的所有方法。例如,我不能写:
let my_result: OrderedFloat<f64> = float_or_err(-1).unwrap_or_default(6.28);
2条答案
按热度按时间kognpnkq1#
这里的问题是,您希望在
Err
上短路,而max_by_key
函数无法实现。我可能会在for循环中这样做,但这也可以使用短路方法,如try_fold
。将来,使用
try_reduce
会稍微简单一些olmpazwi2#
下面是一个传播错误的
max_by_key()
的通用版本: