Menu
CoddyTech

Trait Drop

Thuộc phần Lập trình hướng đối tượng trong hành trình Rust của Coddy. Bài học 56 trên 61.

Khi một giá trị ra khỏi phạm vi trong Rust, nó sẽ tự động được dọn dẹp. Nhưng nếu bạn cần chạy code tùy chỉnh vào lúc đó, chẳng hạn như ghi nhật ký, giải phóng tài nguyên hoặc gửi thông báo cuối cùng thì sao? Trait Drop cho phép bạn xác định chính xác điều gì xảy ra khi struct sắp bị hủy.

Trait Drop có một phương thức duy nhất tên là drop, nhận &mut self:

struct Connection {
    id: u32,
}

impl Drop for Connection {
    fn drop(&mut self) {
        println!("Connection {} closed.", self.id);
    }
}

Bạn không bao giờ gọi trực tiếp drop: Rust tự động gọi hàm này khi giá trị ra khỏi phạm vi:

fn main() {
    let conn = Connection { id: 42 };
    println!("Using connection...");
}  // "Connection 42 closed." tự động in ra ở đây

Đầu ra sẽ là:

Using connection...
Connection 42 closed.

Đây là phiên bản hàm hủy (destructor) của Rust. Hàm này thường dùng cho các tác vụ dọn dẹp: đóng handle tệp, ngắt kết nối với máy chủ hoặc giải phóng tài nguyên mà Rust không thể tự quản lý. Trait Drop đảm bảo code dọn dẹp của bạn vẫn chạy, kể cả khi phạm vi kết thúc do lệnh return sớm.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống quản lý tài nguyên minh họa cách tự động dọn dẹp! Bạn sẽ tạo một struct FileHandle mô phỏng việc mở và đóng tệp. Khi handle ra khỏi phạm vi, nó sẽ tự động thông báo rằng tệp đã đóng.

Bạn sẽ tổ chức code trong hai tệp:

  • file_handle.rs: Định nghĩa một struct FileHandle công khai với trường filename công khai (String). Triển khai hàm liên kết new để tạo một FileHandle và in thông báo khi tệp được "opened". Sau đó, triển khai trait Drop để khi handle bị loại bỏ, nó sẽ in thông báo đóng tệp.
  • main.rs: Đưa module file_handle vào và tạo hàm tên là process_file nhận một filename, tạo một FileHandle bên trong phạm vi cục bộ và in thông báo xử lý khi tệp đang "open". Phần triển khai Drop sẽ tự động chạy khi phạm vi kết thúc. Gọi hàm này với đầu vào đã cho.

Khi tạo FileHandle, chương trình sẽ in:

Opening file: {filename}

Trong khi xử lý (bên trong phạm vi), hãy in:

Processing {filename}...

Khi FileHandle bị loại bỏ (phạm vi kết thúc), chương trình sẽ in:

Closing file: {filename}

Ví dụ, với đầu vào data.txt:

Opening file: data.txt
Processing data.txt...
Closing file: data.txt

Và với đầu vào config.json:

Opening file: config.json
Processing config.json...
Closing file: config.json

Bạn sẽ nhận một đầu vào: chuỗi tên tệp.

Tự làm thử

mod file_handle;

use file_handle::FileHandle;

// TODO: Triển khai hàm (function) process_file
// Hàm này cần:
// 1. Tạo một phạm vi cục bộ (dùng dấu ngoặc nhọn {})
// 2. Trong phạm vi đó, tạo một FileHandle bằng FileHandle::new()
// 3. In ra thông báo xử lý: "Processing {filename}..."
// 4. Khi phạm vi kết thúc, Drop sẽ tự động được gọi
fn process_file(filename: &str) {
    // TODO: Triển khai hàm này
}

fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let filename = input.trim();
    
    process_file(filename);
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Rust online