外观
雷区 5:E0277 trait 约束未满足
报错码:E0277
症状
rust
fn main() {
let mut scores = vec![1.5, 2.5, 0.5];
scores.sort();
println!("{:?}", scores);
}编译输出
text
error[E0277]: the trait bound `{float}: Ord` is not satisfied
--> src/main.rs:3:12
|
3 | scores.sort();
| ^^^^ the trait `Ord` is not implemented for `{float}`
|
= help: the following other types implement trait `Ord`:
i128
i16
i32
i64
i8
isize
u128
...诊断
第 9 章的 trait 约束,真实项目里的头号出场方式:调用一个要求某 trait 的方法,你的类型没实现它。
这个例子特别经典——f64 不能 sort()!为什么?因为 sort 要求 Ord(全序:任何两个值都能比出大小),而浮点数不满足:存在 NaN——NaN 和任何数都"不比大小"(NaN 是"不是一个数",第 16 章 random_range 的小数亲戚)。所以 f64 只有 PartialOrd(可能比不了),没有 Ord。
报错还贴心地列出了哪些类型实现了 Ord:全是整数。这就是为什么"给浮点数排序"要换一种方法。
解药
解药一:用 sort_by + partial_cmp——接受"可能比不了",自己决定怎么办:
rust
fn main() {
let mut scores = vec![1.5, 2.5, 0.5];
scores.sort_by(|a, b| a.partial_cmp(b).unwrap());
println!("{:?}", scores);
}partial_cmp 返回 Option<Ordering>(None 说明比不了,比如有 NaN),.unwrap() 是"我确定没有 NaN"。
解药二:浮点数转整数再排——分数场景,x * 10 变整数:
rust
fn main() {
let mut scores = vec![15, 25, 5]; // 1.5、2.5、0.5 乘 10
scores.sort();
println!("{:?}", scores);
}解药三:给自定义类型实现缺失的 trait——最常见的场景。比如自定义结构体要排序,实现 Ord(或者偷懒用 sort_by_key):
rust
#[derive(Debug)]
struct Pet {
name: String,
cuteness: u32,
}
fn main() {
let mut pets = vec![
Pet { name: String::from("圆圆"), cuteness: 5 },
Pet { name: String::from("小咪"), cuteness: 9 },
];
pets.sort_by_key(|pet| pet.cuteness); // 按可爱度排,不用实现 Ord
println!("{:?}", pets);
}E0277 的读法
E0277 的报错是自解释的:第一行告诉你要什么 trait(Ord),第二行告诉你是谁没满足({float}),help 里还列了谁满足。先读这三行,再决定是"换方法"还是"补实现"。
预防
- 浮点数排序、哈希(做 HashMap 的键)、比较大小,都会撞 E0277——先想"我的类型真的能全序比较吗?"
sort_by_key是神器:按某个字段排,不需要类型实现Ord,只要键类型实现- 自定义类型缺 trait,用
#[derive]能补的优先 derive(Debug/Clone/PartialEq……第 4 章;Ord需要字段都有Ord) - 报错里的 help 列表:"以下类型实现了这个 trait"——扫一眼,通常答案就在里面