Vấn đề
Bạn kiểm tra tài liệu, thấy một phương thức tồn tại cho std::fs::File, và gọi nó. Tuy nhiên, trình biên dịch chặn bạn với lỗi E0599 gây khó chịu. Mặc dù phương thức này là một phần của thư viện chuẩn, Rust vẫn tuyên bố rằng nó không tồn tại trong phạm vi (scope) hiện tại.
error[E0599]: no method named 'read_to_string' found for struct 'File' in the current scope
--> src/main.rs:7:10
|
7 | file.read_to_string(&mut contents)?;
| ^^^^^^^^^^^^^^ method not found in 'File'
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a 'use' for it:
|
1 + use std::io::Read;
|
Cách khắc phục nhanh
Trong Rust, các phương thức được định nghĩa bên trong một trait chỉ hiển thị nếu trait đó được import vào module của bạn. Để sửa lỗi read_to_string trên đối tượng File, hãy thêm dòng import này vào đầu tệp main.rs hoặc lib.rs của bạn:
use std::io::Read;
Nếu bạn đang làm việc với mã bất đồng bộ sử dụng tokio 1.0 trở lên, bạn thường cần extension trait:
use tokio::io::AsyncReadExt;
Tại sao điều này xảy ra?
Nếu bạn chuyển sang từ Java hoặc Python, bạn có thể mong đợi các phương thức được tích hợp trực tiếp vào một class. Rust hoạt động khác. Nó sử dụng các trait để chia sẻ hành vi giữa các kiểu dữ liệu. Một struct như File thực tế không "sở hữu" read_to_string. Thay vào đó, nó triển khai (implement) trait Read, vốn cung cấp chức năng đó.
Thiết kế này giúp ngăn chặn "ô nhiễm không gian tên" (namespace pollution). Nếu không có quy tắc này, việc import một crate mới có thể vô tình thêm hàng tá phương thức vào các biến hiện có của bạn, tiềm ẩn nguy cơ xung đột tên gọi. Bằng cách yêu cầu câu lệnh use rõ ràng, Rust đảm bảo bạn biết chính xác mọi phương thức đến từ đâu.
Ví dụ về mã bị lỗi
Mã bên dưới bị lỗi vì trình biên dịch biết File tồn tại, nhưng nó chưa được chỉ dẫn để tìm kiếm trait Read cho các phương thức khả dụng.
use std::fs::File;
fn main() -> std::io::Result<()> {
let mut file = File::open("config.toml")?;
let mut contents = String::new();
// Lỗi: std::io::Read không nằm trong phạm vi (scope)
file.read_to_string(&mut contents)?;
Ok(())
}
Cách giải quyết lỗi E0599
1. Làm theo lời khuyên của trình biên dịch
Trình biên dịch Rust cực kỳ hữu ích. Nếu bạn nhìn vào đầu ra của lỗi, nó thường xác định chính xác trait bạn cần. Chỉ cần sao chép dòng use được gợi ý và dán vào đầu tệp nguồn của bạn.
2. Import các I/O Trait phổ biến
Nếu bạn đang thực hiện nhiều công việc liên quan đến I/O, bạn có thể import prelude để đưa vào nhiều trait phổ biến cùng một lúc. Bao gồm Read, Write, và BufRead.
use std::io::prelude::*;
3. Kiểm tra các Async Extension Trait
Các crate bất đồng bộ như tokio hoặc futures thường ẩn các phương thức của chúng trong các trait "Extension". Nếu .read() hoặc .write_all() không hoạt động trên một stream async, có khả năng bạn cần một trong những trait sau:
use tokio::io::AsyncReadExt;use tokio::io::AsyncWriteExt;use futures::stream::StreamExt;
4. Kiểm tra kiểu của biến
Đôi khi lỗi E0599 xảy ra vì biến không thuộc kiểu dữ liệu mà bạn nghĩ. Một sai lầm phổ biến là gọi một phương thức trên một Result hoặc Option thay vì giá trị bên trong nó. Ví dụ, File::open trả về một Result<File, Error>.
// Lỗi này xảy ra vì Result không có phương thức read_to_string
let file = File::open("data.txt");
file.read_to_string(&mut s);
// Cách này hoạt động vì toán tử '?' giải nén (unwrap) File
let mut file = File::open("data.txt")?;
file.read_to_string(&mut s);
Bảng tra cứu các Trait phổ biến
Nếu bạn gặp lỗi E0599, hãy kiểm tra xem phương thức của bạn có thuộc về một trong các trait chuẩn sau không:
Phương thức
Trait bắt buộc
`read_to_string`, `read_exact`
`std::io::Read`
`write_all`, `flush`
`std::io::Write`
`next`, `collect`, `map`
`std::iter::Iterator`
`try_into`
`std::convert::TryInto`
`stream.next()` (Async)
`futures::stream::StreamExt`
Để tăng tốc quy trình làm việc của bạn, hãy sử dụng rust-analyzer trong IDE. Nó có thể tự động thêm các lệnh import này cho bạn thông qua tính năng "Quick Fix" (Cmd+. hoặc Alt+Enter) bất cứ khi nào bạn nhập tên phương thức yêu cầu import trait.

