跳转到内容

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 }));
}

^^^ 指向 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”,你却填了“自定义”。“自定义”确实是一个选项,但旁边得把尺寸填上。

枚举变体有三种形状,每种都有自己的写法,创建时和匹配时都是如此(参见枚举可以携带数据):

变体 创建 匹配
单元变体: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.00
1 个圆形
▶ 动手试一试

{ .. } 对每个结构体变体都适用,不管它有多少个字段。对元组变体,同样的意思写成 (..)。参见用 _ 和 .. 忽略一部分。

修复 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 field
8 + 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 } =>。

小测验

1. 对于 enum Shape { Circle { radius: f64 } },哪个 match 分支能编译?

2. let s = Shape::Circle(2.0); 报了“expected value, found struct variant”。怎么修?

3. 下面哪个可以单独用作 match 模式?

得分: 0 / 3