Rust 错误 E0027:pattern does not mention field x(模式漏写字段)
E0027 的意思是:你用模式拆解一个结构体或枚举变体,比如 let Order { item, quantity } = order;,却没有提到所有字段。在 Rust 里,结构体模式必须交代清楚每一个字段:要么写出它们的名字,要么用 .. 表示“其余的都不要”。这是最友好的错误之一:rustc 会直接打印出修法,而且几乎总是加两个点就行。这个系列的其他错误,请看 Rust 编译错误详解。
error[E0027]: pattern does not mention fields `id`, `paid` --> src/main.rs:10:9 |10 | let Order { item, quantity } = order; // ❌ `id` and `paid` are not mentioned | ^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `id`, `paid` |help: include the missing fields in the pattern |10 | let Order { item, quantity, id, paid } = order; // ❌ `id` and `paid` are not mentioned | ++++++++++help: if you don't care about these missing fields, you can explicitly ignore them |10 | let Order { item, quantity, id: _, paid: _ } = order; // ❌ `id` and `paid` are not mentioned | ++++++++++++++++help: or always ignore missing fields here |10 | let Order { item, quantity, .. } = order; // ❌ `id` and `paid` are not mentioned | ++++第一行的意思是“模式没有提到字段 id 和 paid”。
产生这个错误的程序是这样的:
struct Order { id: u32, item: String, quantity: u32, paid: bool,}
fn main() { let order = Order { id: 1, item: String::from("keyboard"), quantity: 2, paid: true }; let Order { item, quantity } = order; // ❌ `id` and `paid` are not mentioned println!("{} x {}", quantity, item);}这个错误是什么意思
Section titled “这个错误是什么意思”第一行列出了模式漏掉的字段(id 和 paid)。^^^ 划出了整个模式,因为问题不在于某个词写错了,而在于少了东西。
接着 rustc 给出三条 help: 建议。它们都是对的,但意思各不相同:
include the missing fields(把缺少的字段写进模式):写出它们的名字,这样你也会得到变量id和paid。explicitly ignore them(明确地忽略它们):写成id: _, paid: _。你得不到变量,但每个字段都按名字列出来了。always ignore missing fields here(在这里总是忽略缺少的字段):写..。意思是“还有其他字段,我不关心”。
就像门口的一张核对清单,上面写着“每一格都要打勾,或者勾选‘其他:跳过’”。你不能干脆留着空格不管。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”在 Rust 里,结构体模式默认应该是完整的,除非你另外说明。这能让下一个读代码的人看清你的意图。Order { item, quantity, .. } 说的是“我只需要这两个”。Order { id, item, quantity, paid } 说的是“每个字段我都考虑过了”。参见用 _ 和 .. 忽略一部分。
真正的好处在结构体发生变化时才显现。如果有人给 Order 加了一个 discount 字段,按名字列出所有字段的模式就会报 E0027,把你带到可能需要处理新字段的代码那里。而带 .. 的模式会照常编译。Rust 让你自己选择想要哪种行为,但不会替你去猜。
修复 1:加上 .. 忽略其余字段
Section titled “修复 1:加上 .. 忽略其余字段”大多数时候都选这个方法。如果你只需要部分字段,就在模式末尾加上 ..。它可以用在 let、match、if let 和函数参数里,而且必须放在最后。
struct Order { id: u32, item: String, quantity: u32, paid: bool,}
fn main() { let order = Order { id: 1, item: String::from("键盘"), quantity: 2, paid: true }; let Order { item, quantity, .. } = order; // ✅ `..` 跳过了 `id` 和 `paid` println!("{} 个{}", quantity, item);
let orders = [ Order { id: 2, item: String::from("鼠标"), quantity: 1, paid: false }, Order { id: 3, item: String::from("显示器"), quantity: 1, paid: true }, ]; for order in &orders { match order { Order { paid: true, item, .. } => println!("发货:{}", item), Order { id, .. } => println!("订单 #{} 等待付款", id), } }}输出:
2 个键盘订单 #2 等待付款发货:显示器注意第一个分支里的 paid: true:模式里的字段也可以拿来和一个值比较,.. 照样会处理其余字段。
修复 2:写出缺少的字段,或者用 _ 按名字忽略它
Section titled “修复 2:写出缺少的字段,或者用 _ 按名字忽略它”当你确实需要这个字段,或者希望以后加字段时模式会报错,选这个方法。对带命名字段的枚举变体做 match,也会出现同样的错误:
error[E0027]: pattern does not mention field `y` --> src/main.rs:9:9 |9 | Message::Move { x } => println!("move to x = {}", x), // ❌ `y` is not mentioned | ^^^^^^^^^^^^^^^^^^^ missing field `y`背后的程序:
enum Message { Move { x: i32, y: i32 }, Quit,}
fn main() { let m = Message::Move { x: 1, y: 2 }; match m { Message::Move { x } => println!("move to x = {}", x), // ❌ `y` is not mentioned Message::Quit => println!("quit"), }}移动有两个坐标,代码其实应该两个都用上。所以把 y 写出来。如果某个字段确实无关紧要,y: _ 能把这一点明明白白地说出来,同时仍然按名字列出了它:
enum Message { Move { x: i32, y: i32 }, Quit,}
fn main() { let messages = [Message::Move { x: 1, y: 2 }, Message::Move { x: 5, y: 0 }, Message::Quit]; for m in &messages { match m { Message::Move { x, y: 0 } => println!("沿着地面滑到 x = {}", x), Message::Move { x, y } => println!("移动到 ({}, {})", x, y), // ✅ 两个字段都有 Message::Quit => println!("退出"), } }
// 每个字段都按名字列出:给 `Move` 加字段时,这里会故意报错 if let Message::Move { x, y: _ } = &messages[0] { println!("第一个 x = {}", x); }}输出:
移动到 (1, 2)沿着地面滑到 x = 5退出第一个 x = 1如果你写出一个字段只是为了忽略它,请写 y: _,而不是单独一个 y。单独写一个从不使用的 y,会得到“unused variable”(未使用的变量)警告。
修复 3:改正拼错的字段名
Section titled “修复 3:改正拼错的字段名”当 E0027 和 E0026 一起出现在同一行时,选这个方法。比如变体的字段叫 radius,你却写了 Shape::Circle { r },就会同时得到两个错误:r 报 E0026(没有这个字段),radius 报 E0027(没有提到)。rustc 在 E0027 的 help 里会建议你在 r 旁边加上 radius,但那并不是你想要的。真正的修法是把错的名字换掉:写成 Shape::Circle { radius },或者写成 Shape::Circle { radius: r } 保留短变量名。这样两个错误会一起消失。示例见 E0026 页面。
给结构体加字段之后。 你给 Order 加了 created_at,于是每个列出了所有字段的模式都报 E0027。这正是检查在发挥作用。逐个判断:这段代码需要 created_at 吗?需要就写出它,不需要就加 ..。
函数参数。 fn print_order(&Order { item, quantity }: &Order) 同样会报 E0027。修复:&Order { item, quantity, .. }。参见在 let 和函数参数里使用模式。
元组结构体和元组变体。 对于 struct Color(u8, u8, u8);,模式 Color(r) 也是不完整的,但 rustc 报的是 E0023:“this pattern has 1 field, but the corresponding tuple struct has 3 fields”(这个模式有 1 个字段,而对应的元组结构体有 3 个字段)。修法是同一个思路:Color(r, ..) 或 Color(r, _, _)。
- E0026:struct or variant does not have a field named x:模式里写了一个不存在的字段名。常常和 E0027 一起出现。
- E0063:missing field in initializer:创建结构体时的同一个道理:每个字段都需要一个值(或者用
..Default::default())。 - E0004:non-exhaustive patterns:
match没有覆盖每一个变体,而 E0027 说的是每一个字段。 E0023: this pattern has N fields, but the corresponding tuple struct has M fields:元组结构体的版本(见上文)。- 所有编译错误:错误页面的完整列表。
小测验
1. struct Point { x: i32, y: i32, z: i32 }。哪个模式能编译,并且只取出 x?
2. Order { item, .. } 和 Order { item, id: _, quantity: _, paid: _ } 有什么区别?
3. 同一行上,r 报了 E0026,radius 报了 E0027。最好的修法是什么?
得分: 0 / 3
- E0027 — Rust error codes index(英文):这个错误的官方解释。
- 模式语法 — Rust 程序设计语言:解构结构体,以及怎样用
..忽略值的其余部分。 - 解构结构体 — 通过例子学 Rust:带
..的结构体模式的可运行示例。 - Patterns — The Rust Reference(英文):结构体模式和剩余模式(rest pattern)的确切规则。