Lỗi Rust E0560: struct has no field named X (struct không có field này)
E0560 nghĩa là: bạn đang tạo một struct bằng Name { field: value }, và một trong các field (trường) bạn viết không tồn tại trong struct đó. Thường đó là lỗi gõ nhầm, một field đã bị đổi tên, hoặc một field thuộc về struct khác. rustc thường cho bạn biết chính xác cái tên bạn định viết, nên đây là một trong những lỗi sửa nhanh nhấ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[E0560]: struct `User` has no field named `nmae` --> src/main.rs:9:9 |9 | nmae: String::from("Ferris"), // ❌ typo: the field is `name` | ^^^^ unknown field |help: a field with a similar name exists |9 - nmae: String::from("Ferris"), // ❌ typo: the field is `name`9 + name: String::from("Ferris"), // ❌ typo: the field is `name` |Trình biên dịch báo struct User không có field nào tên nmae và gợi ý field có tên gần giống là name. Đây là chương trình gây ra lỗi:
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { nmae: String::from("Ferris"), // ❌ typo: the field is `name` active: true, }; println!("{}", user.email);}Ý nghĩa
Phần tiêu đề “Ý nghĩa”Dòng tiêu đề nêu tên struct (User) và field bạn đã viết (nmae). Dấu ^^^^ chỉ vào field đó bên trong khối User { ... }. Rust đã so sánh nó với danh sách field trong struct User và không tìm thấy cái nào khớp.
Dưới mũi tên, bạn sẽ nhận một trong ba gợi ý. Mỗi gợi ý nói một điều khác nhau:
help: a field with a similar name exists: lỗi gõ nhầm. rustc cho thấy dòng code với tên đúng.note: available fields are: `username`: không có tên nào gần giống. Đây là những field bạn chưa điền.note: all struct fields are already assigned: bạn đã điền đủ mọi field thật, và field này là thừa.
Hãy để ý rằng rustc không phàn nàn thêm rằng name bị thiếu. Sửa lỗi gõ là cả hai vấn đề cùng biến mất.
Giống như điền một tờ đơn giấy và ghi số điện thoại vào ô “Fax”. Tờ đơn không có ô đó, nên nhân viên trả lại cho bạn.
Vì sao Rust làm vậy
Phần tiêu đề “Vì sao Rust làm vậy”Các field của một struct được cố định khi bạn viết struct User { ... }. Mỗi lần bạn tạo một User, Rust kiểm tra rằng bạn đưa đúng những field đó: không thiếu, không thừa, không sai chính tả. Xem Định nghĩa và tạo struct.
Điều này bắt được những bug thật. Trong JavaScript, { nmae: "Ferris" } âm thầm tạo ra một object với key sai, và user.name là undefined ở một chỗ nào đó rất lâu sau. Trong Rust, lỗi gõ không thể lọt qua trình biên dịch, nên mọi User trong chương trình của bạn thật sự có name.
Cách sửa
Phần tiêu đề “Cách sửa”Cách sửa 1: Sửa lại chính tả
Phần tiêu đề “Cách sửa 1: Sửa lại chính tả”Chọn cách này khi bạn thấy a field with a similar name exists. Dùng tên trong dòng help:. Tên field phân biệt chữ hoa chữ thường, và Rust dùng snake_case, nên userName và user_name là hai tên khác nhau.
Cũng hãy cẩn thận với cú pháp viết tắt khi khởi tạo field (field init shorthand): User { nmae, email } nghĩa là User { nmae: nmae, email: email }, nên tên biến phải trùng với tên field. Hoặc đổi tên biến, hoặc viết đầy đủ field: User { name: nmae, email }.
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), // ✅ tên field thật active: true, }; println!("{} ({}) đang hoạt động: {}", user.name, user.email, user.active);
// viết tắt: tên biến trùng với tên field let name = String::from("Ada"); let other = User { name, email, active: false }; println!("{} ({}) đang hoạt động: {}", other.name, other.email, other.active);}Kết quả:
Ferris ([email protected]) đang hoạt động: trueAda ([email protected]) đang hoạt động: falseCách sửa 2: Dùng tên mới của field, hoặc thêm field
Phần tiêu đề “Cách sửa 2: Dùng tên mới của field, hoặc thêm field”Chọn cách này khi không có gợi ý “similar name”. Thường là struct đã thay đổi: ai đó đổi name thành username, hoặc một field đã bị xóa, nhưng code này vẫn dùng cái cũ. rustc liệt kê những gì còn lại:
error[E0560]: struct `User` has no field named `name` --> src/main.rs:8:9 |8 | name: String::from("Ferris"), | ^^^^ `User` does not have this field | = note: available fields are: `username`Bạn có hai lựa chọn hợp lý. Nếu struct đúng, hãy dùng tên field hiện tại của nó. Nếu code của bạn đúng và struct thật sự cần field đó, hãy thêm nó vào định nghĩa struct. Ở đây Config báo all struct fields are already assigned cho debug, và cách sửa là thêm debug vào struct:
struct User { username: String, // đổi tên từ `name`: hãy dùng tên mới email: String,}
struct Config { port: u16, host: String, debug: bool, // thêm vào struct, vì code cần nó}
fn main() { let user = User { username: String::from("ferris"), }; println!("{} ({})", user.username, user.email);
let config = Config { port: 8080, host: String::from("localhost"), debug: true, }; println!("{}:{} debug={}", config.host, config.port, config.debug);}Kết quả:
ferris ([email protected])localhost:8080 debug=trueNếu struct đến từ một crate bạn vừa cập nhật, field có thể đã bị đổi tên trong phiên bản mới. Hãy xem struct đó trên docs.rs (tiếng Anh) cho phiên bản ấy, hoặc changelog của crate. Khi bạn thêm một field vào struct của mình, mọi chỗ tạo struct đó cũng phải điền nó. rustc sẽ chỉ ra từng chỗ bằng E0063 (xem bên dưới).
Cách sửa 3: Dùng đúng struct
Phần tiêu đề “Cách sửa 3: Dùng đúng struct”Chọn cách này khi field bạn viết có tồn tại, chỉ là ở một struct khác. Với hai struct giống nhau, như một Product có title và một Customer có name, rất dễ nhầm lẫn:
error[E0560]: struct `Product` has no field named `name` --> src/main.rs:13:9 |13 | name: String::from("Keyboard"), | ^^^^ `Product` does not have this field | = note: available fields are: `title`Hãy nhìn ghi chú available fields. Nếu nó liệt kê những field bạn không mong đợi, bạn đang tạo nhầm struct. Hãy dùng đúng tên struct, hoặc tên field của struct bạn định dùng:
struct Product { title: String, price: u32, // tính bằng xu}
struct Customer { name: String, email: String,}
fn main() { let keyboard = Product { title: String::from("bàn phím"), // sản phẩm có `title` price: 4900, }; let buyer = Customer { name: String::from("Ana"), // khách hàng có `name` }; println!("{} mua một {} giá {} xu", buyer.name, keyboard.title, keyboard.price); println!("Hóa đơn đã gửi đến {}", buyer.email);}Kết quả:
Ana mua một bàn phím giá 4900 xuHóa đơn đã gửi đến [email protected]Cách sửa 4: Dùng dấu ngoặc tròn cho tuple struct
Phần tiêu đề “Cách sửa 4: Dùng dấu ngoặc tròn cho tuple struct”Chọn cách này khi struct là một tuple struct, như struct Point(i32, i32);. Các field của nó không có tên, nên Point { x: 1, y: 2 } cho ra E0560 cho cả x lẫn y, kèm help: `Point` is a tuple struct, use the appropriate syntax và gợi ý Point(/* i32 */, /* i32 */). Hãy tạo nó bằng dấu ngoặc tròn, Point(1, 2), và đọc bằng .0 và .1. Nếu bạn thích có tên hơn, hãy đổi định nghĩa thành struct Point { x: i32, y: i32 }. Xem Khi nào dùng tuple, khi nào dùng struct.
Ngược lại: E0063 thiếu field
Phần tiêu đề “Ngược lại: E0063 thiếu field”Anh em sinh đôi của E0560 là E0063: một field mà struct có, nhưng bạn chưa điền. Rust không bao giờ tự điền field giúp bạn, nên field nào cũng cần một giá trị:
error[E0063]: missing field `active` in initializer of `User` --> src/main.rs:8:16 |8 | let user = User { | ^^^^ missing `active`Khi thiếu nhiều field, nó liệt kê tất cả: missing fields `active`, `email` and `login_count` in initializer of `User`. Cách sửa: cho mọi field một giá trị. Nếu nhiều field có giá trị mặc định hợp lý, hãy derive Default và dùng cú pháp cập nhật struct (struct update syntax) .. để điền phần còn lại:
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool, language: String,}
fn main() { // viết ra đủ mọi field let full = Settings { volume: 80, dark_mode: false, language: String::from("en") };
// chỉ những field bạn quan tâm, phần còn lại lấy từ Default let quick = Settings { dark_mode: true, ..Default::default() };
// sao chép phần còn lại từ một giá trị khác let louder = Settings { volume: 100, ..full };
println!("{:?}", quick); println!("{:?}", louder);}Kết quả:
Settings { volume: 0, dark_mode: true, language: "" }Settings { volume: 100, dark_mode: false, language: "en" }Giá trị mặc định của một số là 0, của bool là false, và của String là chuỗi rỗng. Nếu bạn muốn giá trị mặc định khác, hãy tự viết impl Default for Settings. Xem Default: một giá trị khởi đầu hợp lý.
Thường gặp ở đâu
Phần tiêu đề “Thường gặp ở đâu”Bên trong cú pháp cập nhật ... Settings { dark: true, ..defaults } cũng cho ra E0560. Ở đây ghi chú liệt kê tất cả các field (available fields are: `volume`, `dark_mode`, `language`), và có thể không có gợi ý “similar name” khi các tên quá khác nhau. Cách sửa: dark_mode: true.
Biến thể enum có field được đặt tên. Với enum Shape { Circle { radius: f64 } }, viết Shape::Circle { r: 2.0 } là cùng một lỗi, nhưng rustc dùng mã khác: E0559, variant `Shape::Circle` has no field named `r`, cũng với ghi chú available fields và gợi ý lỗi gõ. Cách sửa: Shape::Circle { radius: 2.0 }. Xem Enum có thể chứa dữ liệu.
Một struct từ module khác. Nếu field có tồn tại nhưng không pub, bạn sẽ nhận E0451, “field balance of struct Account is private”. Cách sửa: dùng hàm khởi tạo của module, như Account::new(...). Xem Mọi thứ mặc định là riêng tư.
Lỗi liên quan
Phần tiêu đề “Lỗi liên quan”- E0609: no field
xon typeT: cùng lỗi gõ nhầm, nhưng khi đọc một field (user.nmae) thay vì tạo struct. - E0451: field is private in struct literal: field có tồn tại nhưng bạn không thể gán nó từ chỗ này.
- E0308: mismatched types: tên field đúng, nhưng giá trị sai kiểu, như
"Ferris"cho một fieldString. E0063: missing field in initializer: một field bạn đã quên (xem ở trên).E0559: variant has no field named x: E0560 dành cho biến thể enum.- 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. rustc nói note: all struct fields are already assigned. Điều đó nghĩa là gì?
2. Bạn có let nmae = ...; và viết User { nmae, email }. Sửa thế nào?
3. Bạn nhận lỗi nào khi bỏ sót một field, như User { name, email } mà không có active?
Điểm: 0 / 3
Đọc thêm
Phần tiêu đề “Đọc thêm”- E0560 — Rust error codes index (tiếng Anh): giải thích chính thức về lỗi này.
- Defining and Instantiating Structs — The Rust Book (tiếng Anh): struct literal, cú pháp viết tắt khi khởi tạo field, cú pháp cập nhật struct và tuple struct.
- E0063 — Rust error codes index (tiếng Anh): trang chính thức cho lỗi “thiếu field”, anh em sinh đôi của lỗi này.
- Struct expressions — The Rust Reference (tiếng Anh): quy tắc chính xác cho
Name { field: value }, cách viết tắt và..base. Default— thư viện chuẩn Rust (tiếng Anh): cách#[derive(Default)]và..Default::default()hoạt động.