Lỗi Rust E0425: cannot find value in this scope (không tìm thấy tên)
Lỗi E0425 nghĩa là Rust đã tìm một cái tên ở đúng một vị trí trong code của bạn và không thấy nó ở đó. Đây là một trong những lỗi phổ biến nhất, và gần như lúc nào cũng sửa nhanh: thường là gõ sai chính tả, một biến nằm trong một khối khác, hoặc một hàm cần đường dẫn module của nó. Trang này thuộc hướng dẫn về lỗi trình biên dịch.
Thông báo lỗi
Phần tiêu đề “Thông báo lỗi”error[E0425]: cannot find value `total_scor` in this scope --> src/main.rs:3:33 |3 | println!("Final score: {}", total_scor); | ^^^^^^^^^^ |help: a local variable with a similar name exists |3 | println!("Final score: {}", total_score); | +Thông báo của trình biên dịch luôn bằng tiếng Anh: “cannot find value total_scor in this scope” nghĩa là “không tìm thấy giá trị total_scor trong phạm vi này”. Đây là chương trình gây ra lỗi đó (chuỗi được giữ bằng tiếng Anh vì nó xuất hiện nguyên văn trong thông báo lỗi):
fn main() { let total_score = 42; println!("Final score: {}", total_scor);}Ý nghĩa
Phần tiêu đề “Ý nghĩa”Các dấu ^^^^ đánh dấu cái tên mà Rust không tìm thấy: total_scor ở dòng 3. “In this scope” nghĩa là “tính từ chỗ dòng này đang đứng”. Rust đã kiểm tra mọi biến, hàm và import nhìn thấy được tại điểm đó, và không có cái nào mang tên ấy.
Hãy đọc cả dòng help:. Ở đây rustc phát hiện một biến có tên gần giống (total_score) và còn chỉ ra chữ cái bị thiếu bằng dấu +. Khi bạn thấy “a local variable with a similar name exists” (có một biến cục bộ với tên tương tự), đó là lỗi gõ sai.
Giống như bạn gọi to “Tun ơi!” trong phòng trong khi bạn mình tên là Tuấn. Bạn ấy ở ngay đó, nhưng chẳng ai trả lời cái tên “Tun” cả.
Lỗi này cũng xuất hiện dưới dạng cannot find function ... in this scope khi cái tên bị thiếu là một hàm mà bạn gọi.
Vì sao Rust làm vậy
Phần tiêu đề “Vì sao Rust làm vậy”Trước khi chương trình chạy, Rust quyết định mỗi cái tên trỏ tới cái gì. Một biến chỉ tồn tại từ dòng let của nó cho đến dấu } đóng của khối nơi nó được khai báo. Đó là phạm vi (scope) của nó. Ra ngoài vùng đó, cái tên đơn giản là không tồn tại.
Nhiều ngôn ngữ sẽ để bạn “thoát” lỗi này, và bạn chỉ phát hiện về sau. Trong JavaScript, một lỗi gõ sai có thể lặng lẽ tạo ra một biến toàn cục mới hoặc cho bạn undefined. Trong Python bạn sẽ gặp NameError lúc chạy, có khi chỉ trên đúng nhánh code mà test của bạn không bao giờ chạm tới. Rust bắt được nó lúc biên dịch, lần nào cũng vậy.
Hàm cũng theo cùng ý tưởng đó với module: một hàm bên trong mod billing không nhìn thấy được từ main cho đến khi bạn ghi đường dẫn của nó hoặc đưa nó vào bằng use.
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 dòng help: nói có một tên tương tự. Đây là nguyên nhân phổ biến nhất, bỏ xa các nguyên nhân khác. Tên trong Rust cũng phân biệt chữ hoa chữ thường, nên Total_score và total_score là hai tên khác nhau.
fn main() { let total_score = 42; println!("Điểm cuối cùng: {}", total_score);}Kết quả:
Điểm cuối cùng: 42Cách sửa 2: Khai báo biến ở chỗ cả hai nơi đều nhìn thấy
Phần tiêu đề “Cách sửa 2: Khai báo biến ở chỗ cả hai nơi đều nhìn thấy”Chọn cách này khi phần help nói “the binding is available in a different scope in the same function” (biến này có ở một phạm vi khác trong cùng hàm). Bạn tạo biến bên trong một vòng lặp hoặc khối if, rồi dùng nó sau dấu }. Phiên bản bị lỗi trông như thế này:
fn main() { let prices = [120, 300, 80]; for price in prices { let with_tax = price + price / 10; println!("{with_tax}"); } println!("Giá cuối cùng có thuế: {}", with_tax); // error[E0425]}with_tax được tạo mới ở mỗi lượt lặp và bị bỏ đi tại dấu } của vòng lặp. Nếu bạn cần một giá trị sau vòng lặp, hãy khai báo nó trước vòng lặp và cập nhật nó bên trong:
fn main() { let prices = [120, 300, 80]; let mut last_with_tax = 0;
for price in prices { let with_tax = price + price / 10; println!("{with_tax}"); last_with_tax = with_tax; }
println!("Giá cuối cùng có thuế: {}", last_with_tax);}Kết quả:
13233088Giá cuối cùng có thuế: 88Cách sửa này cũng dùng được nếu bạn dùng một biến trước dòng let của nó. Rust đọc từ trên xuống dưới, nên chỉ cần dời dòng let lên trên.
Cách sửa 3: Ghi đường dẫn của hàm, hoặc thêm use
Phần tiêu đề “Cách sửa 3: Ghi đường dẫn của hàm, hoặc thêm use”Chọn cách này với cannot find function khi hàm nằm trong một module khác. Rust in ra:
error[E0425]: cannot find function `total_with_tax` in this scope --> src/main.rs:8:17 |8 | let total = total_with_tax(50.0); | ^^^^^^^^^^^^^^ not found in this scope |help: consider importing this function |1 + use crate::billing::total_with_tax; |Phần help gợi ý import hàm đó. Bạn có thể gọi nó bằng đường dẫn đầy đủ (billing::total_with_tax(50.0)) hoặc thêm dòng use mà rustc gợi ý:
mod billing { pub fn total_with_tax(amount: f64) -> f64 { amount * 1.2 }}
use crate::billing::total_with_tax;
fn main() { let total = total_with_tax(50.0); println!("{total}");}Kết quả:
60Hàm cũng phải là pub. Nếu không, bạn sẽ gặp một lỗi khác (E0603, “function is private”, hàm là private). Xem Module để biết đường dẫn và use hoạt động thế nào.
Cách sửa 4: Thêm self. trước tên trường
Phần tiêu đề “Cách sửa 4: Thêm self. trước tên trường”Chọn cách này bên trong một phương thức, khi cái tên bị thiếu là một trường của struct. Nếu bạn đến từ Java hay C#, việc viết count và mong nó trỏ tới trường là rất tự nhiên. Trong Rust bạn luôn viết self.count. rustc sẽ nói: help: you might have meant to use the available field (có lẽ bạn muốn dùng trường đang có).
struct Counter { count: u32,}
impl Counter { fn report(&self) { println!("Số đếm: {}", self.count); }}
fn main() { let c = Counter { count: 3 }; c.report();}Kết quả:
Số đếm: 3Thường gặp ở đâu
Phần tiêu đề “Thường gặp ở đâu”-
Một biến được gán bên trong
if.if balance > 50 { let bonus = 10; }rồiprintln!("{}", bonus)sẽ lỗi, vìbonusđã “chết” ở dấu}. Cách sửa: choiftạo ra giá trị,let bonus = if balance > 50 { 10 } else { 0 };. -
Gọi hàm khởi tạo mà không ghi kiểu.
let p = new("ferris");báocannot find function `new` in this scope. Cách sửa:newthuộc về kiểu, nên hãy viếtPlayer::new("ferris"). -
Dùng
selftrong một hàm không có tham sốself. Đây là “người anh em họ” gần gũi của E0425, E0424:error[E0424]: expected value, found module `self`--> src/main.rs:7:9|6 | fn reset() {| ----- this function doesn't have a `self` parameter7 | self.count = 0;| ^^^^ `self` value is a keyword only available in methods with a `self` parameterThông báo nói rằng hàm này không có tham số
self, vàselfchỉ dùng được trong phương thức có tham sốself. Cách sửa: thêm tham sốself. rustc gợi ý&self, nhưng hàm này thay đổi một trường, nên nó cầnfn reset(&mut self).
Lỗi liên quan
Phần tiêu đề “Lỗi liên quan”- E0599: no method found: cái tên bạn gọi như một phương thức không tồn tại trên kiểu đó.
- E0382: use of moved value: biến có tồn tại, nhưng giá trị của nó đã bị move đi.
- E0308: mismatched types: tìm thấy cái tên, nhưng nó sai kiểu.
- E0277: trait bound not satisfied: một kiểu thiếu trait mà một đoạn code nào đó cần.
- Tất cả lỗi trình biên dịch: danh sách đầy đủ, kèm tóm tắt ngắn cho từng lỗi.
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. rustc nói "help: a local variable with a similar name exists". Nguyên nhân khả dĩ nhất là gì?
2. Bạn viết let found = true; bên trong một vòng lặp for và dùng found sau vòng lặp. Vì sao lại lỗi?
3. Hàm send nằm trong mod mailer. Dòng nào cho phép main gọi nó bằng send()?
Điểm: 0 / 3
Đọc thêm
Phần tiêu đề “Đọc thêm”- E0425 — Rust error codes index (tiếng Anh): phần giải thích chính thức, kèm thêm ví dụ.
- Bringing Paths into Scope with use — The Rust Book (tiếng Anh): cách
uselàm cho hàm ở module khác nhìn thấy được. - Scope and Shadowing — Rust by Example (tiếng Anh): các ví dụ ngắn về nơi một biến sinh ra và mất đi.
- Method Syntax — The Rust Book (tiếng Anh): vì sao phương thức dùng
selfvà cách truy cập trường qua nó. - E0424 — Rust error codes index (tiếng Anh): lỗi liên quan khi dùng
selfbên ngoài phương thức.