Bỏ qua để đến nội dung

Giải thích các lỗi trình biên dịch Rust

Trình biên dịch Rust vừa báo một lỗi đỏ chót và bạn chưa hiểu nó muốn gì? Bạn đến đúng chỗ rồi. Lập trình viên Rust nào cũng gặp những lỗi này, thường là nhiều lần mỗi ngày. Tin vui là: chỉ có một nhóm nhỏ lỗi mà bạn sẽ gặp đi gặp lại, và khi đã quen với chúng, chúng không còn đáng sợ nữa.

Mỗi trang bên dưới nói về một mã lỗi: cho bạn xem thông báo thật, giải thích bằng lời dễ hiểu, và đưa ra các cách sửa mà bạn có thể chạy ngay trên trình duyệt.

Lỗi Trình biên dịch nói gì Nói đơn giản là
E0382 borrow of moved value Bạn đã trao giá trị đi, rồi lại cố dùng nó lần nữa
E0502 cannot borrow as mutable because it is also borrowed as immutable Bạn sửa một thứ trong khi vẫn còn chỗ khác đang đọc nó
E0499 cannot borrow as mutable more than once at a time Hai nơi cùng muốn sửa một thứ vào cùng lúc
E0308 mismatched types Bạn đưa một kiểu trong khi chỗ đó cần kiểu khác
E0277 the trait bound is not satisfied Một kiểu không làm được việc bạn yêu cầu (in ra, so sánh, cộng…)
E0106 missing lifetime specifier Rust không biết tham chiếu được trả về còn hợp lệ trong bao lâu
E0425 cannot find value in this scope Một cái tên bị gõ sai, hoặc được dùng bên ngoài khối nơi nó tồn tại
E0599 no method named … found Kiểu đó không có phương thức này, hoặc trait của nó chưa được import
E0384 cannot assign twice to immutable variable Bạn thay đổi một biến không được khai báo mut
E0596 cannot borrow as mutable, as it is not declared as mutable Bạn cố thay đổi một thứ qua biến hoặc tham chiếu không phải mut
E0597 borrowed value does not live long enough Một tham chiếu vẫn đang được dùng sau khi giá trị mà nó trỏ tới đã mất
E0515 cannot return reference to local variable Bạn trả về tham chiếu tới một thứ sẽ bị hủy khi hàm kết thúc
E0373 closure may outlive the current function, but it borrows … Một closure (thường là luồng) mượn một biến cục bộ có thể đã mất trước khi nó chạy
E0369 binary operation == cannot be applied to type … Kiểu của bạn (chưa) hỗ trợ ==, <, + và các toán tử tương tự
E0432 unresolved import Một dòng use trỏ tới crate, module hoặc thành phần không tìm thấy
E0433 cannot find type … in this scope (older: failed to resolve) Một đường dẫn như HashMap::new() dùng tên chưa được import hoặc không tồn tại
E0424 self value is a keyword only available in methods with a self parameter Bạn dùng self trong một hàm không nhận self
E0061 this function takes N arguments but M arguments were supplied Bạn truyền thừa hoặc thiếu đối số (Rust không có đối số tùy chọn)
E0594 cannot assign to p.hp, as p is not declared as mutable Bạn thay đổi một trường hoặc một giá trị sau & mà không có quyền mut
E0004 non-exhaustive patterns: X not covered match của bạn chưa xử lý hết mọi giá trị có thể
E0507 cannot move out of x which is behind a shared reference Bạn cố lấy quyền sở hữu một thứ mà bạn chỉ đang mượn
E0603 function x is private Bạn dùng một hàm, struct hoặc module không phải pub
E0716 temporary value dropped while borrowed Bạn giữ tham chiếu tới một giá trị bị bỏ đi ngay cuối dòng
E0463 can’t find crate for x Một crate (hoặc thư viện chuẩn cho một target) chưa được cài
E0368 binary assignment operation += cannot be applied to type … Kiểu của bạn không hỗ trợ +=, -= và các toán tử tương tự
E0057 this function takes N arguments but M were supplied (note: closure defined here) Bạn gọi một closure với thừa hoặc thiếu đối số
E0282 type annotations needed Rust không tự suy ra được một kiểu, nên bạn phải ghi rõ
E0609 no field x on type T Tên trường bị gõ sai, hoặc giá trị đang được bọc (ví dụ trong Option)
E0593 closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments Closure nhận các đối số riêng lẻ trong khi chỗ đó cần một tuple (hoặc số lượng khác)
E0631 type mismatch in closure arguments Kiểu tham số của closure không khớp với thứ nó nhận được (thường là i32 với &i32)
E0005 refutable pattern in local binding let Some(x) = … có thể thất bại, nên let thường không chấp nhận
E0615 attempted to take value of method len on type String Bạn viết s.len thay vì s.len()
E0610 {integer} is a primitive type and therefore doesn’t have fields Bạn dùng .field trên một số, bool hoặc char
E0560 struct User has no field named nmae Khi tạo struct, bạn dùng một tên trường mà struct không có
E0616 field balance of struct Account is private Bạn đọc một trường không phải pub từ bên ngoài module của nó
E0451 field x of struct Y is private Bạn tạo struct bằng cú pháp literal trong khi có trường là private
E0624 method x is private Bạn gọi một phương thức hoặc hàm liên kết không phải pub
E0283 type annotations needed (cannot infer type … multiple impls satisfy this bound) Có nhiều kiểu cùng hợp (ví dụ .collect(), .sum()), nên bạn phải chọn một
E0284 type annotations needed: cannot satisfy <_ as FromStr>::Err == _ "42".parse() không biết phải phân tích thành kiểu nào
E0790 cannot call associated function on trait without specifying the corresponding impl type Bạn viết Default::default() hoặc Trait::new() mà không nói rõ kiểu nào
E0559 variant Shape::Circle has no field named r Khi tạo một biến thể enum, bạn dùng tên trường mà biến thể đó không có
E0063 missing field email in initializer of User Bạn tạo struct nhưng bỏ sót một hoặc vài trường
E0689 can’t call method pow on ambiguous numeric type {integer} 2.pow(10) hay 2.0.sqrt() cần một kiểu số cụ thể như i32 hoặc f64
E0034 multiple applicable items in scope Hai trait cho kiểu của bạn một phương thức cùng tên, nên Rust không chọn được
E0412 cannot find type X in this scope (Rust 1.93+ prints E0425) Tên kiểu bị gõ sai, chưa import hoặc chưa khai báo
E0428 the name area is defined multiple times Hai thành phần dùng chung một tên; Rust không có nạp chồng hàm (overloading)
E0026 variant Shape::Circle does not have a field named r Một mẫu nhắc tới trường mà struct hoặc biến thể không có
E0027 pattern does not mention fields id, paid Mẫu struct bỏ sót trường; hãy thêm vào hoặc kết thúc bằng ..
E0533 expected unit struct, unit variant or constant, found struct variant Shape::Circle Một biến thể dạng struct (hoặc một hàm) được dùng ở chỗ cần một tên đơn thuần; thêm { .. }
E0592 duplicate definitions with name reset Hai khối impl định nghĩa phương thức trùng tên
E0255 the name Error is defined multiple times Một dòng use import một tên trùng với kiểu hoặc hàm của chính bạn
E0252 the name Result is defined multiple times Hai dòng use đưa vào cùng một tên; đổi tên một cái bằng as
E0411 cannot find type Self in this scope Bạn dùng Self bên ngoài impl hoặc trait
E0405 cannot find trait Display in this scope Tên trait bị gõ sai hoặc chưa import (ví dụ use std::fmt::Display;)
E0532 expected unit struct, unit variant or constant, found tuple variant Shape::Circle Mẫu ghi tên một biến thể tuple (hoặc struct) mà thiếu ( ), hoặc thêm ( ) ở chỗ không cần
E0164 expected tuple struct or tuple variant, found struct variant Shape::Circle Mẫu dùng ( ) cho biến thể dạng struct hoặc thành phần liên kết; hãy dùng { } hoặc guard
E0404 expected trait, found derive macro Debug Bạn viết impl X for hoặc T: X trong khi X là struct, alias hoặc derive macro chưa import
E0401 can’t use generic parameters from outer item Một fn bên trong dùng T hoặc Self của hàm bên ngoài; cho nó generic riêng hoặc dùng closure
E0107 enum takes 2 generic arguments but 1 generic argument was supplied Result<u32>, HashMap<String> và những trường hợp tương tự: thiếu hoặc thừa đối số trong < >
E0530 match bindings cannot shadow tuple variants Một tên biến thể trần như Circle => (sau use Shape::*) không thể là biến mới
E0434 can’t capture dynamic environment in a fn item Một fn bên trong không thấy được biến cục bộ bên ngoài; dùng closure hoặc truyền vào
E0601 main function not found in crate main Chương trình không có fn main() (thiếu, gõ sai, nằm trong mod, hoặc thực ra là thư viện)
E0658 use of unstable library feature iter_intersperse Bạn dùng API chỉ có trên nightly với Rust stable; dùng cách thay thế stable hoặc cập nhật
E0614 type u32 cannot be dereferenced Bạn viết *x trong khi x đã là giá trị thường, không phải tham chiếu
E0435 attempt to use a non-constant value in a constant Một const, độ dài mảng hoặc static dùng biến let; đổi nó thành const hoặc dùng Vec
E0554 #![feature] may not be used on the stable release channel Code chép từ nightly; bỏ thuộc tính đó và dùng API stable, hoặc chủ động dùng nightly

Thông báo lỗi của Rust nổi tiếng là hữu ích, nhưng chúng chứa khá nhiều thông tin. Đây là một lỗi thật:

fn main() {
let name = String::from("Ferris");
let greeting = name;
println!("{name}");
}
error[E0382]: borrow of moved value: `name`
--> src/main.rs:4:16
|
2 | let name = String::from("Ferris");
| ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
3 | let greeting = name;
| ---- value moved here
4 | println!("{name}");
| ^^^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let greeting = name.clone();
| ++++++++

Thông báo của trình biên dịch luôn bằng tiếng Anh. Hãy đọc nó theo thứ tự này:

  1. Dòng đầu tiên là phần tóm tắt: mã lỗi (E0382) và một dòng mô tả.
  2. Dòng có mũi tên (--> src/main.rs:4:16) cho bạn biết file, dòng và cột nơi xảy ra vấn đề.
  3. Các dấu ^^^^ chỉ đúng vị trí của lỗi. Các dấu ---- là “câu chuyện” dẫn tới lỗi đó. Ở đây chúng nói: giá trị được tạo ở dòng 2, bị move (di chuyển) ở dòng 3, rồi lại được dùng ở dòng 4.
  4. help: là cách sửa mà trình biên dịch gợi ý, thường kèm đúng đoạn code cần thêm (các dấu ++++ cho thấy ký tự mới). Đó không phải lúc nào cũng là cách sửa tốt nhất, nhưng là điểm khởi đầu rất tốt.

Hãy bắt đầu đọc từ lỗi đầu tiên. Một sai sót có thể kéo theo cả chuỗi lỗi phía sau, và sửa lỗi đầu tiên thường làm những lỗi còn lại biến mất.

  • Hỏi trình biên dịch thêm. Mỗi mã lỗi đều có sẵn một phần giải thích dài hơn. Hãy chạy lệnh này trong terminal:

    Terminal window
    rustc --explain E0382

    Bạn sẽ nhận được một mô tả ngắn, một ví dụ lỗi và một ví dụ đã sửa (bằng tiếng Anh).

  • Kiểm tra thường xuyên. cargo check tìm lỗi mà không cần build cả chương trình, nên nhanh hơn cargo build rất nhiều. Chạy nó sau mỗi vài dòng code nghĩa là bạn gặp từng lỗi một, chứ không phải hai mươi lỗi một lúc. Xem Cargo và crate.

  • Để trình soạn thảo hiện lỗi ngay khi bạn gõ. Với tiện ích rust-analyzer, lỗi hiện ngay trong code của bạn, kèm cùng phần gợi ý. Xem Công cụ và cài đặt Rust.

Phần lớn các lỗi này tồn tại vì Rust kiểm tra trước khi chương trình chạy những thứ mà các ngôn ngữ khác chỉ phát hiện lúc chạy (hoặc không bao giờ): dùng vùng nhớ đã giải phóng, hai luồng cùng sửa một dữ liệu, quên kiểm tra null. Mỗi lỗi bạn sửa là một bug sẽ không bao giờ đến tay người dùng.

Vì vậy nhiều người nói: với Rust, cuộc chiến diễn ra lúc biên dịch, sau đó chương trình cứ thế chạy. Các quy tắc đằng sau những lỗi thường gặp nhất được giải thích trong Quyền sở hữu, Mượn và Lifetime.

Kiểm tra nhanh

1. Một lỗi Rust báo nhiều vấn đề. Bạn nên sửa cái nào trước?

2. Lệnh rustc --explain E0382 làm gì?

3. Trong thông báo lỗi, các dấu ^^^^ cho thấy điều gì?

Điểm: 0 / 3