Lỗi Rust E0559: variant has no field named X (biến thể không có field này)
E0559 nghĩa là: bạn đang tạo một giá trị enum bằng Enum::Variant { field: value }, và một trong các field (trường) bạn viết không tồn tại trong biến thể (variant) đó. Đây là phiên bản enum của E0560, cùng sai lầm nhưng với struct. Thường đó là một tên field viết tắt hoặc sai chính tả, một field thuộc về biến thể khác, hoặc dùng dấu ngoặc nhọn cho một biến thể cần dấu ngoặc tròn. Cách sửa gần như luôn chỉ là một từ. (Trang này thuộc loạt bài Giải thích các lỗi trình biên dịch Rust.)
Thông báo lỗi
Phần tiêu đề “Thông báo lỗi”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`Trình biên dịch báo biến thể Shape::Circle không có field nào tên r, và liệt kê các field có sẵn: radius. Đây là chương trình gây ra lỗi:
#[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);}Ý nghĩa
Phần tiêu đề “Ý nghĩa”Dòng tiêu đề nêu tên biến thể (Shape::Circle) và field bạn đã viết (r). Dấu ^ chỉ vào field đó bên trong dấu ngoặc nhọn. Rust đã xem định nghĩa Circle { radius: f64 } và không tìm thấy field nào tên r.
Mỗi biến thể của enum có danh sách field riêng. Shape::Circle có radius, Shape::Rectangle có width và height. Chúng không dùng chung field, kể cả khi nằm trong cùng một enum.
Dưới mũi tên, rustc đưa ra một trong các gợi ý sau. Hãy đọc nó trước, vì nó thường chứa sẵn câu trả lời:
note: available fields are: `radius`: không có tên nào gần giống. Đây là các field mà biến thể này có và bạn chưa điền.help: a field with a similar name exists: lỗi gõ nhầm, nhưkyethay chokey. rustc cho thấy dòng đã sửa.help: `Message::Write` is a tuple variant, use the appropriate syntax: các field của biến thể không có tên, nên nó cần( ), không phải{ }.note: all struct fields are already assigned: bạn đã điền đủ mọi field thật, và field này là thừa.
Giống như gọi pizza và yêu cầu “đế to” trong khi thực đơn chỉ có “cỡ đế”. Nhà bếp hiểu rõ bạn muốn gì, nhưng phiếu gọi món không có ô nào mang tên đó.
Vì sao Rust làm vậy
Phần tiêu đề “Vì sao Rust làm vậy”Một biến thể enum có field được đặt tên, như Circle { radius: f64 }, hoạt động như một struct nhỏ bên trong enum. Khi bạn tạo nó, Rust kiểm tra rằng bạn đưa đúng các field của nó: không thiếu, không thừa, không sai chính tả. Xem Enum có thể chứa dữ liệu.
Điều này quan trọng nhất khi sau đó bạn match trên enum. Nhánh Shape::Circle { radius } => ... chỉ chạy được nếu mọi Circle thật sự có radius. Nếu Rust cho Shape::Circle { r: 2.0 } lọt qua, sự đảm bảo đó sẽ mất. Bắt lỗi gõ ngay lúc biên dịch giữ cho mọi Circle trong chương trình của bạn luôn đầy đủ.
Cách sửa
Phần tiêu đề “Cách sửa”Cách sửa 1: Dùng đúng tên field của biến thể
Phần tiêu đề “Cách sửa 1: Dùng đúng tên field của biến thể”Chọn cách này khi rustc hiện available fields are hoặc a field with a similar name exists. Hãy dùng tên trong gợi ý. Tên field phân biệt chữ hoa chữ thường và được viết theo snake_case, nên Radius và radius là khác nhau.
Một lỗi gõ nhầm sẽ có gợi ý “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' }; |Một tên ngắn như r khác radius quá nhiều để được gợi ý, nên bạn nhận danh sách field thay vào đó. Dù thế nào, hãy viết đúng field mà biến thể định nghĩa:
#[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 }, // ✅ tên field thật 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);}Kết quả:
Circle { radius: 2.0 }Rectangle { width: 3.0, height: 4.0 }[KeyPress { key: 'a' }, Click { x: 10, y: 20 }]Hãy cẩn thận với cú pháp viết tắt khi khởi tạo field (field init shorthand). Shape::Circle { r } nghĩa là Shape::Circle { r: r }, nên nó cũng cho ra E0559. Nếu biến của bạn tên là r, hãy viết đầy đủ field: Shape::Circle { radius: r }. Hoặc đổi tên biến thành radius rồi viết Shape::Circle { radius }.
Cách sửa 2: Dùng dấu ngoặc tròn cho tuple variant
Phần tiêu đề “Cách sửa 2: Dùng dấu ngoặc tròn cho tuple variant”Chọn cách này khi rustc nói is a tuple variant, use the appropriate syntax. Một biến thể như Write(String) có một field, nhưng field đó không có tên. Vì vậy tên nào bạn viết trong dấu ngoặc nhọn cũng sai:
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 */ trong gợi ý là chỗ giữ chỗ: hãy đặt giá trị của bạn vào đó. Tạo một tuple variant bằng dấu ngoặc tròn, theo đúng thứ tự trong định nghĩa:
#[derive(Debug)]enum Message { Move { x: i32, y: i32 }, // field có tên: dùng { } Write(String), // field không tên: dùng ( ) Color(u8, u8, u8),}
fn main() { let messages = vec![ Message::Move { x: 1, y: 2 }, Message::Write(String::from("chào")), // ✅ ngoặc tròn Message::Color(255, 128, 0), ]; for m in &messages { match m { Message::Move { x, y } => println!("di chuyển đến ({}, {})", x, y), Message::Write(text) => println!("viết: {}", text), Message::Color(r, g, b) => println!("màu: {} {} {}", r, g, b), } }}Kết quả:
di chuyển đến (1, 2)viết: chàomàu: 255 128 0Nếu bạn thích đặt tên cho field, hãy đổi định nghĩa thành Write { text: String }. Khi đó Message::Write { text: ... } chạy được. Sự nhầm lẫn ngược lại, dùng ngoặc tròn cho một biến thể có field được đặt tên như Shape::Circle(2.0), cho ra một lỗi khác: E0533, “expected value, found struct variant”.
Cách sửa 3: Chọn đúng biến thể, hoặc thay đổi biến thể
Phần tiêu đề “Cách sửa 3: Chọn đúng biến thể, hoặc thay đổi biến thể”Chọn cách này khi field bạn viết có tồn tại, chỉ là ở một biến thể khác. Ở đây radius thuộc về Circle, không thuộc về 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`Hãy tự hỏi bạn định dùng cái nào. Nếu bạn muốn một hình tròn, hãy dùng Shape::Circle { radius: 2.0 }. Nếu bạn muốn một hình vuông, hãy dùng field của nó: Shape::Square { side: 2.0 }.
Nếu bạn thấy note: all struct fields are already assigned, biến thể đã đủ field và field của bạn là thừa. Hãy bỏ nó đi, hoặc, nếu code của bạn thật sự cần nó, hãy thêm nó vào định nghĩa của biến thể:
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
#[derive(Debug)]enum Message { Move { x: i32, y: i32, z: i32 }, // thêm `z`, vì code cần nó}
fn main() { let a = Shape::Circle { radius: 2.0 }; // hình tròn có bán kính let b = Shape::Square { side: 2.0 }; // hình vuông có cạnh println!("{:?} và {:?}", a, b);
let m = Message::Move { x: 1, y: 2, z: 3 }; println!("{:?}", m);}Kết quả:
Circle { radius: 2.0 } và Square { side: 2.0 }Move { x: 1, y: 2, z: 3 }Khi bạn thêm một field vào biến thể, mọi chỗ tạo biến thể đó cũng phải điền nó. rustc chỉ ra từng chỗ bằng E0063, “missing field”.
Thường gặp ở đâu
Phần tiêu đề “Thường gặp ở đâu”Phương thức khởi tạo với Self::. Bên trong impl Shape, viết fn circle(r: f64) -> Shape { Self::Circle { r } } cho ra E0559 cho r, vì cú pháp viết tắt. Cách sửa: Self::Circle { radius: r }. Xem Enum cũng có thể có phương thức.
Sau khi đổi tên một field. Bạn đổi Circle { r } thành Circle { radius } trong enum, và mọi chỗ Shape::Circle { r: ... } cũ giờ cho ra E0559 với available fields are: `radius`. Hãy tìm tên cũ trong cả project và cập nhật từng chỗ.
Trong một mẫu match. Viết sai tên field trong một mẫu (pattern), như Shape::Circle { r } => ..., là cùng sai lầm, nhưng rustc dùng mã khác: E0026, “variant Shape::Circle does not have a field named r”, kèm help: `Shape::Circle` has a field named `radius`, cộng thêm E0027 “pattern does not mention field radius”. Cách sửa: Shape::Circle { radius } => ..., hoặc Shape::Circle { radius: r } => ... để giữ tên ngắn. Xem So khớp mẫu.
Lỗi liên quan
Phần tiêu đề “Lỗi liên quan”- E0560: struct has no field named x: cùng sai lầm với một struct literal, như
User { nmae: ... }. - E0063: missing field in initializer: ngược lại, một field mà biến thể có nhưng bạn chưa điền.
- E0599: no method named x found: rustc dùng cùng mã này khi tên biến thể sai, như
Shape::Circel { ... }. rustc nói “no variant namedCircelfound for enumShape”. - E0609: no field on type: sai tên field khi đọc một field.
E0026: variant does not have a field named x: cùng sai lầm bên trong một mẫumatch(xem ở trên).E0533: expected value, found struct variant: dùng ngoặc tròn cho một biến thể có field được đặt tên, nhưShape::Circle(2.0).- Giải thích tất cả các lỗi trình biên dịch
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. Với enum Message { Write(String) }, Message::Write { text: s } cần trở thành gì?
2. Bạn có let r = 2.0; và viết Shape::Circle { r }, nhưng field là radius. Cách sửa là gì?
3. Shape::Square { radius: 2.0 } cho ra E0559, và ghi chú chỉ liệt kê side. Chuyện gì đang xảy ra?
Điểm: 0 / 3
Đọc thêm
Phần tiêu đề “Đọc thêm”- E0559 — Rust error codes index (tiếng Anh): giải thích chính thức về lỗi này.
- Defining an Enum — The Rust Book (tiếng Anh): biến thể có field được đặt tên, tuple variant và unit variant, với ví dụ
Message. - Enums — Rust by Example (tiếng Anh): ví dụ chạy được cho mọi loại biến thể.
- Struct expressions — The Rust Reference (tiếng Anh): quy tắc chính xác cho
Enum::Variant { field: value }, kể cả cách viết tắt. - E0026 — Rust error codes index (tiếng Anh): trang chính thức cho cùng sai lầm bên trong một mẫu.