Rust 错误 E0533:expected unit struct, unit variant or constant, found struct variant(漏写大括号)
E0533 的意思是:你单独写了一个像 Shape::Circle 这样的名字,可在那个位置,光有名字是不够的。最常见的情况是一个带命名字段的枚举变体(Circle { radius: f64 })漏写了 { },不管是在 match 分支里还是在创建值的时候。少数情况下,是在只能放固定值的地方写了一个函数或方法。只要明白 rustc 要的是什么,两种情况都很快就能修好。这个系列的其他错误,请看 Rust 编译错误详解。
error[E0533]: expected unit struct, unit variant or constant, found struct variant `Shape::Circle` --> src/main.rs:8:9 |8 | Shape::Circle => "circle", // ❌ `Circle` has a field | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant |help: the struct variant's field is being ignored |8 | Shape::Circle { radius: _ } => "circle", // ❌ `Circle` has a field | +++++++++++++第一行的意思是“这里应该是单元结构体、单元变体或常量,却找到了结构体变体 Shape::Circle”。
产生这个错误的程序是这样的:
enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle` has a field Shape::Square { .. } => "square", }}
fn main() { println!("{}", name(&Shape::Square { side: 2.0 }));}这个错误是什么意思
Section titled “这个错误是什么意思”^^^ 指向 Shape::Circle,第一行说明了那里允许出现什么:一个只有名字的模式,必须是下面三者之一:
- 单元结构体(unit struct),比如
struct Empty; - 单元变体(unit variant),也就是不带数据的变体,比如
Shape::Empty或None - 常量,比如
const MAX: u32 = 100;
Shape::Circle 哪个都不是。它是一个结构体变体(struct variant):它带着一个 radius。单独一个 Shape::Circle 能匹配“一个圆”,却对它的字段只字不提,而 Rust 要求模式的形状和变体的形状一致。help: 行给出了修法:加上大括号。它的意思是“结构体变体的字段被忽略了”。
E0533 的第二种形式写的是 expected value, found struct variant(这里应该是一个值,却找到了结构体变体)。是同一种混淆,只不过发生在创建值的时候,通常是用圆括号写成了 Shape::Circle(2.0)。
就像一张快递单上有一栏写着“尺寸:S、M 或 L”,你却填了“自定义”。“自定义”确实是一个选项,但旁边得把尺寸填上。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”枚举变体有三种形状,每种都有自己的写法,创建时和匹配时都是如此(参见枚举可以携带数据):
| 变体 | 创建 | 匹配 |
|---|---|---|
单元变体:Empty |
Shape::Empty |
Shape::Empty |
元组变体:Point(f64, f64) |
Shape::Point(1.0, 2.0) |
Shape::Point(x, y) 或 Shape::Point(..) |
结构体变体:Circle { radius: f64 } |
Shape::Circle { radius: 2.0 } |
Shape::Circle { radius } 或 Shape::Circle { .. } |
严格区分形状,意味着模式总是长得和它匹配的东西一样,读 match 时就能清楚知道每个分支拿到了哪些数据。这也意味着当某个变体的形状改变时,比如 Empty 多了一个字段,每个还在用旧形状的地方都会被标出来,而不是悄悄地做错事。
修复 1:在模式里加上 { .. } 或字段
Section titled “修复 1:在模式里加上 { .. } 或字段”当错误指向 match、if let 或 matches! 的分支,并且写着 found struct variant 时,选这个方法。不需要字段就写 { .. },需要就写出字段名。rustc 建议的 { radius: _ } 也可以,{ .. } 是同一个意思的更短写法。
enum Shape { Circle { radius: f64 }, Square { side: f64 }, Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "圆形", // ✅ “一个圆,不管半径是多少” Shape::Square { .. } => "正方形", Shape::Empty => "空", // 单元变体:不需要大括号 }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle { radius } => 3.14 * radius * radius, // ✅ 需要字段,所以写出字段名 Shape::Square { side } => side * side, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle { radius: 1.0 }, Shape::Square { side: 3.0 }, Shape::Empty]; for shape in &shapes { println!("{}:{:.2}", name(shape), area(shape)); } let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle { .. })).count(); println!("{} 个圆形", circles);}输出:
圆形:3.14正方形:9.00空:0.001 个圆形{ .. } 对每个结构体变体都适用,不管它有多少个字段。对元组变体,同样的意思写成 (..)。参见用 _ 和 .. 忽略一部分。
修复 2:用大括号和字段名创建值
Section titled “修复 2:用大括号和字段名创建值”当信息写着 expected value, found struct variant 时,选这个方法。你把结构体变体当成元组变体来创建了(或者根本没给字段):
error[E0533]: expected value, found struct variant `Shape::Circle` --> src/main.rs:8:17 |8 | let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field | ^^^^^^^^^^^^^ not a value |help: you might have meant to create a new value of the struct |8 - let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle` has a named field |help: 的意思是“你可能是想创建这个结构体的一个新值”。背后的程序:
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn main() { let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field println!("{:?}", shape);}建议里的 /* value */ 是给你的值留的占位符。结构体变体的字段要在大括号里按名字设置:
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
impl Shape { // 一个简短的构造函数,如果你想写 `Shape::circle(2.0)` fn circle(radius: f64) -> Shape { Shape::Circle { radius } }}
fn main() { let a = Shape::Circle { radius: 2.0 }; // ✅ 大括号加字段名 let b = Shape::Square { side: 1.5 }; let c = Shape::circle(0.5); println!("{:?}", a); println!("{:?}", b); println!("{:?}", c);}输出:
Circle { radius: 2.0 }Square { side: 1.5 }Circle { radius: 0.5 }如果你更想写 Shape::Circle(2.0),就把定义改成元组变体:Circle(f64)。只有一个意思很明显的字段时,这是个不错的选择;字段多的时候,命名字段更清楚。
修复 3:用常量或匹配守卫代替函数
Section titled “修复 3:用常量或匹配守卫代替函数”当信息写着 found associated function(找到了关联函数)时,选这个方法。方法也会出现这个错误,比如 String::len。模式必须是编译时就已知的值。函数调用不是,所以函数名不能用作模式:
error[E0533]: expected unit struct, unit variant or constant, found associated function `Limits::max_users` --> src/main.rs:12:9 |12 | Limits::max_users => "full", // ❌ a function can't be a pattern | ^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant背后的程序:
struct Limits;
impl Limits { fn max_users() -> u32 { 100 }}
fn status(users: u32) -> &'static str { match users { 0 => "empty", Limits::max_users => "full", // ❌ a function can't be a pattern _ => "open", }}
fn main() { println!("{}", status(100));}如果这个值永远不变,就把它改成 const。常量可以用作模式。如果它必须计算出来,就保留函数,在 if 匹配守卫里比较:
struct Limits;
impl Limits { const MAX_USERS: u32 = 100; // 常量可以用作模式
fn max_rooms(premium: bool) -> u32 { if premium { 20 } else { 5 } }}
fn status(users: u32) -> &'static str { match users { 0 => "空闲", Limits::MAX_USERS => "已满", // ✅ 一个常量 _ => "开放中", }}
fn rooms_status(rooms: u32, premium: bool) -> &'static str { match rooms { n if n >= Limits::max_rooms(premium) => "不能再加房间了", // ✅ 在守卫里调用 _ => "还可以再加一个房间", }}
fn main() { println!("{}", status(0)); println!("{}", status(100)); println!("{}", status(42)); println!("{}", rooms_status(5, false)); println!("{}", rooms_status(5, true));}输出:
空闲已满开放中不能再加房间了还可以再加一个房间匹配守卫的讲解见匹配守卫:再加一个 if。
单元变体有了字段之后。 Status::Done 原本是单元变体,你把它改成了 Done { at: u64 }。现在每个 Status::Done => 分支和每个 let s = Status::Done; 都会报 E0533。修复:在模式里写 Status::Done { .. } =>,在创建它的地方写 Status::Done { at: 0 }(填上真实的值)。
从其他语言转过来。 在 Java 或 TypeScript 里,你可能会写 case Circle: 只检查值的种类。在 Rust 里,要写 Shape::Circle { .. } =>,或者用 matches!(shape, Shape::Circle { .. }) 快速得到一个 bool。
元组变体的版本。 对于元组变体,比如 Circle(f64),单独写一个 Shape::Circle => 分支会得到另一个代码 E0532,第一行一样是“expected unit struct, unit variant or constant, found tuple variant Shape::Circle”。修复是 Shape::Circle(_) 或 Shape::Circle(..)。反过来,在模式里给结构体变体加圆括号,比如对 Circle { radius: f64 } 写 Shape::Circle(r) =>,会得到 E0164:“expected tuple struct or tuple variant, found struct variant”(这里应该是元组结构体或元组变体,却找到了结构体变体)。修复:Shape::Circle { radius: r } =>。
- E0559:variant has no field named x:大括号是对的,但里面有个字段名写错了。
- E0026:struct or variant does not have a field named x:模式大括号里的字段名写错了。
- E0027:pattern does not mention field x:模式里有大括号,却漏了字段;加上
..。 - E0004:non-exhaustive patterns:分支修好之后,
match仍然必须覆盖每一个变体。 E0532: expected unit struct, unit variant or constant, found tuple variant:元组变体的版本(见上文)。- 所有编译错误:错误页面的完整列表。
小测验
1. 对于 enum Shape { Circle { radius: f64 } },哪个 match 分支能编译?
2. let s = Shape::Circle(2.0); 报了“expected value, found struct variant”。怎么修?
3. 下面哪个可以单独用作 match 模式?
得分: 0 / 3
- E0533 — Rust error codes index(英文):这个错误的官方解释。
- 模式语法 — Rust 程序设计语言:解构枚举、用
..忽略值,以及匹配守卫。 - 解构枚举 — 通过例子学 Rust:把单元变体、元组变体和结构体变体的匹配放在一起对比。
- E0532 — Rust error codes index(英文):这个错误的元组变体版本的官方页面。
- Patterns — The Rust Reference(英文):哪些路径可以用作模式,以及结构体模式和元组结构体模式的规则。