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

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.

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);
}

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.

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.

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: 42
▶ Tự chạy thử

Cá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ả:

132
330
88
Giá cuối cùng có thuế: 88
▶ Tự chạy thử

Cá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ả:

60
▶ Tự chạy thử

Hà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: 3
▶ Tự chạy thử
  • Một biến được gán bên trong if. if balance > 50 { let bonus = 10; } rồi println!("{}", bonus) sẽ lỗi, vì bonus đã “chết” ở dấu }. Cách sửa: cho if tạ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áo cannot find function `new` in this scope. Cách sửa: new thuộc về kiểu, nên hãy viết Player::new("ferris").

  • Dùng self trong 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` parameter
    7 | self.count = 0;
    | ^^^^ `self` value is a keyword only available in methods with a `self` parameter

    Thông báo nói rằng hàm này không có tham số self, và self chỉ 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ần fn reset(&mut self).

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