在 Rust 中为 Option<number> 做 max 的惯用方法
Idiomatic way to do max for Option<number> in Rust
我在Option
中有一个号码。我需要用它的最大值和其他一些值替换它,或者如果我的号码是 None
.
,则使用其他值
我写了一个函数来这样做:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
if a.is_some() {
Some(std::cmp::max(a.unwrap(), b))
} else {
Some(b)
}
}
但我一直在想,使用 Option
的方法有更好、更简洁的方法来做到这一点。你能帮帮我吗?
使用map
:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
a.map(|v| std::cmp::max(v, b))
}
或map_or
默认展开的术语:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
a.map_or(Some(b), |v| Some(std::cmp::max(v, b)))
}
您实际上不需要返回的 Option
:
fn max(a: Option<u32>, b: u32) -> u32 {
a.map_or(b, |v| std::cmp::max(v, b))
}
...对于那些函数式编程书呆子...
使用 monad 属性的另一种方法,也许这可以帮助您理解 monad,它允许给定 Thing<A>
应用函数 A -> Thing<B>
以获得 Thing<B>
:
and_then :: Thing<A> -> (A -> Thing<B>) -> Thing<B>
fn max(a: Option<u32>, b: u32) -> u32 {
a.and_then(|v| Some(std::cmp::max(v, b))).unwrap_or(b)
}
Option<T>
implements Ord
当 T
实现 Ord
时,您将能够比较 Option<T>
值。
因为std::cmp::max<T: Ord>(...)
做比较,所以可以这样实现你的功能:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
std::cmp::max(a, Some(b))
}
请注意,对于每个 T: Ord
,Some<T>
都大于 None
,这满足您的要求。
这没有记录在案,但我可以这么说,因为 Ord
类型构成了 total order。这意味着它需要是可传递的;如果 None
小于 Some(MIN)
,则 None
将小于集合中的任何其他值 (Option<T>
),因为 Some(MIN)
小于任何值在集合中,除了 None
assert!(Some(std::i64::MIN) > None);
您还可以通过添加额外的 or
来扩展 std::cmp::min
,这也适用于 max
的情况,但不需要这样做,因为会有额外的检查和额外的副本值 b
比较 max
.
的解决方案
fn min(a: Option<u32>, b: u32) -> Option<u32> {
std::cmp::min(a.or(Some(b)), Some(b))
}
我在Option
中有一个号码。我需要用它的最大值和其他一些值替换它,或者如果我的号码是 None
.
我写了一个函数来这样做:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
if a.is_some() {
Some(std::cmp::max(a.unwrap(), b))
} else {
Some(b)
}
}
但我一直在想,使用 Option
的方法有更好、更简洁的方法来做到这一点。你能帮帮我吗?
使用map
:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
a.map(|v| std::cmp::max(v, b))
}
或map_or
默认展开的术语:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
a.map_or(Some(b), |v| Some(std::cmp::max(v, b)))
}
您实际上不需要返回的 Option
:
fn max(a: Option<u32>, b: u32) -> u32 {
a.map_or(b, |v| std::cmp::max(v, b))
}
...对于那些函数式编程书呆子...
使用 monad 属性的另一种方法,也许这可以帮助您理解 monad,它允许给定 Thing<A>
应用函数 A -> Thing<B>
以获得 Thing<B>
:
and_then :: Thing<A> -> (A -> Thing<B>) -> Thing<B>
fn max(a: Option<u32>, b: u32) -> u32 {
a.and_then(|v| Some(std::cmp::max(v, b))).unwrap_or(b)
}
Option<T>
implements Ord
当 T
实现 Ord
时,您将能够比较 Option<T>
值。
因为std::cmp::max<T: Ord>(...)
做比较,所以可以这样实现你的功能:
fn max(a: Option<u32>, b: u32) -> Option<u32> {
std::cmp::max(a, Some(b))
}
请注意,对于每个 T: Ord
,Some<T>
都大于 None
,这满足您的要求。
这没有记录在案,但我可以这么说,因为 Ord
类型构成了 total order。这意味着它需要是可传递的;如果 None
小于 Some(MIN)
,则 None
将小于集合中的任何其他值 (Option<T>
),因为 Some(MIN)
小于任何值在集合中,除了 None
assert!(Some(std::i64::MIN) > None);
您还可以通过添加额外的 or
来扩展 std::cmp::min
,这也适用于 max
的情况,但不需要这样做,因为会有额外的检查和额外的副本值 b
比较 max
.
fn min(a: Option<u32>, b: u32) -> Option<u32> {
std::cmp::min(a.or(Some(b)), Some(b))
}