Ghi chú học Rust - Sở hữu ba Phân đoạn - chơi trò chơi bắn cá

Ngoài cách tham chiếu, Rust còn cung cấp một kiểu dữ liệu khác không sở hữu quyền sở hữu: phân đoạn (slice). Phân đoạn cho phép chúng ta trỏ đến một dãy các phần tử liên tiếp trong một tập hợp, thay vì toàn bộ tập hợp đó. Ví dụ như đoạn mã sau:

1fn main() {  
2    let mut s = String::from("hello world");  
3    let word = first_word(&s);  
4    s.clear(); // Lúc này, dù word vẫn là 5 nhưng s đã bị xóa sạch, nên nó không còn ý nghĩa gì nữa.
5}

Trong ví dụ trên, rõ ràng rằng chúng ta cần phải theo dõi sự tồn tại của biến s. Để đảm bảo tính hợp lý của logic chương trình, chúng ta cần có thêm biện pháp kiểm soát. Đây chính là lúc mà phân đoạn (slice) phát huy tác dụng.

1let s = String::from("hello world");  
2let hello = &s[0..5];  
3let world = &s[6..11];

Cách viết này tương tự như cú pháp list trong Python, với những cải tiến đặc biệt từ Rust. Chẳng hạn, bạn có thể bỏ qua số lượng cuối để chỉ định toàn bộ phần còn lại của chuỗi:

1let hello = &s[0..];

Thậm chí đơn giản hơn nữa:

1let hello = &s[..];

Sau khi sử dụng phân đoạn, chương trình sẽ được cải thiện đáng kể về mặt an toàn và quản lý tài nguyên. Dưới đây là một ví dụ cụ thể:

 1fn first_word(s: &String) -> &str {  
 2    let bytes = s.as_bytes();  
 3    for (i, &item) in bytes.iter().enumerate() {  
 4        if item == b' ' {  
 5            return &s[0..i];  
 6        }  
 7    }  
 8    &s[..]  
 9}  
10
11fn main() {  
12    let mut s = String::from("hello world");  
13    let word = first_word(&s);  
14    s.clear(); // Lỗi! Vì word vẫn đang là một phân đoạn của s và cần đảm bảo s còn tồn tại.  
15    println!("Từ đầu tiên là: {}", word);  
16}

Khi chạy hàm main, chương trình sẽ báo lỗi vì word hiện đang là một phân đoạn và cần đảm bảo rằng s vẫn còn hiệu lực.

Hơn nữa, chúng ta có thể sửa đổi hàm first_word để xử lý cả trường hợp chuỗi đầy đủ (&String) cũng như các phân đoạn bình thường:

1fn first_word(s: &str) -> &str { ... }

Như vậy, hàm này giờ đây linh hoạt hơn rất nhiều, có thể xử lý cả chuỗi hoàn chỉnh lẫn các phân đoạn riêng lẻ.

Đối với các loại phân đoạn khác, chẳng hạn 888bets mảng số:

1let a = [1, 2, 3, 4, 5];  
2let slice = &a[1..3];

Đây chỉ là một ghi chú ngắn gọn. Bạn có thể tìm hiểu chi tiết hơn qua cuốn sách chuyên sâu về Rust.