我正在查看文档,发现了一个看起来不熟悉的示例代码。
use std::cmp::Reverse;
let mut v = vec![1, 2, 3, 4, 5, 6];
v.sort_by_key(|&num| (num > 3, Reverse(num)));
assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);
(num > 3, Reverse(num))
如何定义它们之间的顺序?
我查看了 tuple 的文档,它说
元组的顺序性质适用于其各种特征的实现。例如,在 PartialOrd 和 Ord 中,顺序比较元素,直到找到第一个不相等的集合。
这对于相等性检查是有意义的,但在我看来,它没有解释
>
和 <
如何作用于元组。
我做了一些实验,但什么也不懂。
println!("{}", (5, 5) > (3, 4)); // true
println!("{}", (2, 2) > (3, 4)); // false
println!("{}", (2, 5) > (3, 4)); // false
println!("{}", (3, 5) > (3, 4)); // true
println!("{}", (5, 2) > (3, 4)); // true
正如您引用的注释,元组是按字典顺序比较的。
也就是说,比较每个元组的第一个元素,如果它们相等,则比较第二个元素,然后是第三个元素,依此类推。直到找到不相等的对并提供元组的排序。如果所有对都相等,那么元组显然是相等的。
println!("{}", (5, 5) > (3, 4)); // true
5 > 3,因此 (5, _) > (3, _)
println!("{}", (2, 2) > (3, 4)); // false
2< 3, therefore (2, _) < (3, _)
println!("{}", (2, 5) > (3, 4)); // false
见上文
println!("{}", (3, 5) > (3, 4)); // true
3 == 3, 5 > 4,因此 (3, 5) > (3, 4)
println!("{}", (5, 2) > (3, 4)); // true
参见第一个案例
如何定义它们之间的顺序?(num > 3, Reverse(num))
布尔排序
false < true
,因此它首先对两大类别中的元素进行排序(数字 3 或以下,然后数字大于 3),然后在每个类别中,项目根据其相反的自然顺序(即,最大在先)进行排序。尽管它显然是一次性完成的。
tuple
的源代码:
impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
where last_type!($($T,)+): ?Sized {
#[inline]
fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
lexical_partial_cmp!($(self.$idx, other.$idx),+)
}
// ...
#[inline]
fn gt(&self, other: &($($T,)+)) -> bool {
lexical_ord!(gt, $(self.$idx, other.$idx),+)
}
}
lexical_ord
宏:
// Constructs an expression that performs a lexical ordering using method $rel.
// The values are interleaved, so the macro invocation for
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
// a3, b3)` (and similarly for `lexical_cmp`)
macro_rules! lexical_ord {
($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
if $a != $b { lexical_ord!($rel, $a, $b) }
else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
};
($rel: ident, $a:expr, $b:expr) => { ($a) . $rel (& $b) };
}
因此
(a, b) > (c, d)
将调用 (a, b).gt(&(c, d))
,它将使用像这样的 lexical_ord
宏(请参阅代码中的注释):
lexical_ord(gt, a, c, b, d)
(实际上,如果我正确地阅读了宏,它应该类似于
lexical_ord(gt, (a, b).0, (c, d).0, (a, b).1, (c, d).1)
,但我在这里简化了它。)
这将被翻译(在编译时)为:
if a != c {
(a).gt(&c)
} else {
(b).gt(&d)
}
因此,
(a, b) > (c, d)
调用的实际代码将是:
fn gt(&self, other: &($T, $T)) -> bool {
if self.0 != other.0 {
(self.0).gt(&other.0) // self.0 > other.0
} else {
(self.1).gt(&other.1) // self.1 > other.1
}
}
所以它是一对一地比较每个元组中的值。
这对于相等性检查是有意义的,但在我看来,它没有解释
和>
如何作用于元组。<
确实如此,请考虑您给出的示例:
println!("{}", (5, 5) > (3, 4)); // 5 > 3 is true
println!("{}", (2, 2) > (3, 4)); // 2 > 3 is false
println!("{}", (2, 5) > (3, 4)); // 2 > 3 is false
println!("{}", (3, 5) > (3, 4)); // 3 == 3, then: 5 > 4 is true
println!("{}", (5, 2) > (3, 4)); // 5 > 3 is true
它返回元组第一个不相等元素的
<
/>
的结果。