跳转到内容

Rust 错误 E0559:variant has no field named X(变体没有这个字段)

E0559 的意思是:你在用 Enum::Variant { field: value } 创建一个枚举值,而你写的某个字段在这个变体里并不存在。 它是 E0560 的枚举版本,E0560 是结构体上的同一种错误。通常是字段名写短了或拼错了、用了属于另一个变体的字段,或者给一个应该用圆括号的变体写了花括号。修复几乎总是只改一个词。(本页属于 Rust 编译错误详解系列。)

error[E0559]: variant `Shape::Circle` has no field named `r`
--> src/main.rs:8:33
|
8 | let shape = Shape::Circle { r: 2.0 }; // ❌ the field is called `radius`
| ^ `Shape::Circle` does not have this field
|
= note: available fields are: `radius`

第一行的意思是“变体 Shape::Circle 没有名为 r 的字段”。note 列出了可用的字段:radius。

产生这个错误的程序是这样的:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn main() {
let shape = Shape::Circle { r: 2.0 }; // ❌ the field is called `radius`
println!("{:?}", shape);
}

标题里写出了变体(Shape::Circle)和你写的字段(r)。^ 指向花括号里的那个字段。Rust 查看了定义 Circle { radius: f64 },没有找到叫 r 的字段。

枚举的每个变体都有自己的字段列表。Shape::Circle 有 radius,Shape::Rectangle 有 width 和 height。即使在同一个枚举里,它们也不共用字段。

在箭头下面,rustc 会给出下面某一条提示。先读它,答案通常就在里面:

  • note: available fields are: `radius`:没有相近的名字。列出的是这个变体里你还没有填的字段。
  • help: a field with a similar name exists:拼写错误,比如把 key 写成了 kye。rustc 会给出改正后的那一行。
  • help: `Message::Write` is a tuple variant, use the appropriate syntax:这个变体的字段没有名字,所以要用 ( ),而不是 { }。
  • note: all struct fields are already assigned:真正的字段你都已经填了,这一个是多出来的。

就像点披萨时你说要“大号饼边”,可菜单上只有“饼边尺寸”这一项。厨房完全明白你的意思,但订单上没有叫这个名字的格子。

带命名字段的枚举变体,比如 Circle { radius: f64 },就像枚举里的一个小结构体。创建它时,Rust 会检查你给出的是不是恰好这些字段:不能少、不能多、不能拼错。参见枚举可以携带数据。

这在之后对枚举做 match 时最重要。分支 Shape::Circle { radius } => ... 能成立,前提是每个 Circle 都真的有 radius。如果 Rust 放过了 Shape::Circle { r: 2.0 },这个保证就没了。在编译时抓住拼写错误,才能让程序里的每个 Circle 都是完整的。

当 rustc 显示 available fields are 或 a field with a similar name exists 时,选这个。用提示里给出的名字。字段名区分大小写,并且用 snake_case 书写,所以 Radius 和 radius 是不同的。

拼写错误会得到“similar name”(相近的名字)提示:

error[E0559]: variant `Event::KeyPress` has no field named `kye`
--> src/main.rs:8:31
|
8 | let e = Event::KeyPress { kye: 'a' };
| ^^^ unknown field
|
help: a field with a similar name exists
|
8 - let e = Event::KeyPress { kye: 'a' };
8 + let e = Event::KeyPress { key: 'a' };
|

像 r 这样的短名字和 radius 差得太远,rustc 给不出建议,所以你会看到字段列表。不管哪种情况,都写上变体定义的那个字段:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[derive(Debug)]
enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 }, // ✅ 真正的字段名
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("{:?}", shape);
}
let events = [Event::KeyPress { key: 'a' }, Event::Click { x: 10, y: 20 }];
println!("{:?}", events);
}

输出:

Circle { radius: 2.0 }
Rectangle { width: 3.0, height: 4.0 }
[KeyPress { key: 'a' }, Click { x: 10, y: 20 }]
▶ 动手试一试

小心字段初始化简写。Shape::Circle { r } 的意思是 Shape::Circle { r: r },所以会报同样的 E0559。如果你的变量叫 r,就把字段写全:Shape::Circle { radius: r }。或者把变量改名为 radius,然后写 Shape::Circle { radius }。

当 rustc 说 is a tuple variant, use the appropriate syntax 时,选这个。像 Write(String) 这样的变体有一个字段,但这个字段没有名字。所以你在花括号里写什么名字都是错的:

error[E0559]: variant `Message::Write` has no field named `text`
--> src/main.rs:8:30
|
4 | Write(String),
| ----- `Message::Write` defined here
...
8 | let m = Message::Write { text: String::from("hi") };
| ^^^^ field does not exist
|
help: `Message::Write` is a tuple variant, use the appropriate syntax
|
8 - let m = Message::Write { text: String::from("hi") };
8 + let m = Message::Write(/* String */);
|

建议里的 /* String */ 是一个占位符:把你的值放在那里。用圆括号创建元组变体,顺序和定义里一致:

#[derive(Debug)]
enum Message {
Move { x: i32, y: i32 }, // 命名字段:用 { }
Write(String), // 无名字段:用 ( )
Color(u8, u8, u8),
}
fn main() {
let messages = vec![
Message::Move { x: 1, y: 2 },
Message::Write(String::from("hi")), // ✅ 圆括号
Message::Color(255, 128, 0),
];
for m in &messages {
match m {
Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
Message::Write(text) => println!("写入:{}", text),
Message::Color(r, g, b) => println!("颜色:{} {} {}", r, g, b),
}
}
}

输出:

移动到 (1, 2)
写入:hi
颜色:255 128 0
▶ 动手试一试

如果你更想给字段起个名字,就把定义改成 Write { text: String }。这样 Message::Write { text: ... } 就能用了。反过来的混淆,也就是给带命名字段的变体用圆括号,比如 Shape::Circle(2.0),会得到另一个错误:E0533,“expected value, found struct variant”(期望一个值,却找到了结构体变体)。

修复 3:选对变体,或者修改变体

Section titled “修复 3:选对变体,或者修改变体”

当你写的字段确实存在,只不过在另一个变体里时,选这个。这里 radius 属于 Circle,而不是 Square:

error[E0559]: variant `Shape::Square` has no field named `radius`
--> src/main.rs:8:29
|
8 | let s = Shape::Square { radius: 2.0 };
| ^^^^^^ `Shape::Square` does not have this field
|
= note: available fields are: `side`

问问自己本来想要哪一个。如果想要圆形,就用 Shape::Circle { radius: 2.0 }。如果想要正方形,就用它的字段:Shape::Square { side: 2.0 }。

如果你看到 note: all struct fields are already assigned,说明这个变体的字段已经填齐了,你写的字段是多余的。把它删掉;或者如果代码真的需要它,就把它加进变体的定义里:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
#[derive(Debug)]
enum Message {
Move { x: i32, y: i32, z: i32 }, // 加上了 `z`,因为代码需要它
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // 圆形有半径
let b = Shape::Square { side: 2.0 }; // 正方形有边长
println!("{:?} 和 {:?}", a, b);
let m = Message::Move { x: 1, y: 2, z: 3 };
println!("{:?}", m);
}

输出:

Circle { radius: 2.0 } 和 Square { side: 2.0 }
Move { x: 1, y: 2, z: 3 }
▶ 动手试一试

给变体加了字段以后,所有创建这个变体的地方也都必须填上它。rustc 会用 E0063“missing field”(缺少字段)把每一处都指出来。

用 Self:: 写构造方法。 在 impl Shape 里写 fn circle(r: f64) -> Shape { Self::Circle { r } },因为简写的缘故,会对 r 报 E0559。修复:Self::Circle { radius: r }。参见枚举也可以有方法。

改了字段名之后。 你在枚举里把 Circle { r } 改成了 Circle { radius },于是之前每一处 Shape::Circle { r: ... } 都会报 E0559,并显示 available fields are: `radius`。在项目里搜索旧名字,逐个改掉。

在 match 模式里。 在模式里写错字段名,比如 Shape::Circle { r } => ...,是同一种错误,但 rustc 用的是别的错误代码:E0026,“variant Shape::Circle does not have a field named r”,附带 help: `Shape::Circle` has a field named `radius`,再加上 E0027“pattern does not mention field radius”(模式里没有提到字段 radius)。修复:Shape::Circle { radius } => ...,或者想保留短名字就写 Shape::Circle { radius: r } => ...。参见模式匹配。

小测验

1. 对于 enum Message { Write(String) },Message::Write { text: s } 应该改成什么?

2. 你有 let r = 2.0;,写了 Shape::Circle { r },但字段叫 radius。怎么修?

3. Shape::Square { radius: 2.0 } 报了 E0559,note 里只列出了 side。这是怎么回事?

得分: 0 / 3