0
0
Lập trình
Hưng Nguyễn Xuân 1
Hưng Nguyễn Xuân 1xuanhungptithcm

Ngày 30 #100DaysOfRust: Đếm Tham Chiếu với Rc<T>

Đăng vào 3 tuần trước

• 4 phút đọc

Ngày 30 #100DaysOfRust: Đếm Tham Chiếu với Rc

Hôm nay, chúng ta sẽ khám phá Rc, Con trỏ thông minh đếm tham chiếu trong Rust. Đây là một khía cạnh thú vị của ownership — đôi khi một giá trị cần có nhiều chủ sở hữu, và Rc cung cấp chức năng này một cách chính xác.

🔄 Tại Sao Chọn Rc?

Thông thường, ownership trong Rust là rất nghiêm ngặt: chỉ có một chủ sở hữu cho bất kỳ giá trị nào. Nhưng trong các trường hợp thực tế, nhiều phần của một chương trình có thể cần chia sẻ quyền truy cập. Ví dụ, trong cấu trúc đồ thị, nhiều cạnh có thể chỉ đến cùng một nút. Nút đó không nên bị giải phóng cho đến khi tất cả các cạnh ngừng chỉ đến nó.

Rc<T> giữ một bản theo dõi về số lượng tham chiếu đến một giá trị. Khi tất cả các tham chiếu đã biến mất, giá trị sẽ được giải phóng an toàn.

👉 Hãy nghĩ về Rc như một TV trong phòng khách: mọi người đều có thể xem khi họ ở trong phòng, và chỉ khi người cuối cùng rời đi thì TV mới được tắt.

⚠️ Rc chỉ hoạt động trong các chương trình đơn luồng. Đối với đa luồng, Rust cung cấp Arc<T> (Đếm tham chiếu nguyên tử).

📝 Ví Dụ: Sở Hữu Chia Sẻ trong Danh Sách

Hãy xem lại ví dụ về danh sách cons. Nếu chúng ta sử dụng Box<T> cho ownership, chúng ta sẽ gặp vấn đề:

rust Copy
enum List {
    Cons(i32, Box<List>),
    Nil,
}

use crate::List::{Cons, Nil};

fn main() {
    let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
    let b = Cons(3, Box::new(a));
    let c = Cons(4, Box::new(a)); // ❌ Lỗi: a đã được di chuyển
}

Điều này thất bại vì a đã bị di chuyển vào b, vì vậy nó không thể được sử dụng trong c.

✅ Sửa Chữa Với Rc

Bằng cách sử dụng Rc, chúng ta cho phép sở hữu nhiều:

rust Copy
use std::rc::Rc;

enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    let b = Cons(3, Rc::clone(&a));
    let c = Cons(4, Rc::clone(&a));
}

Ở đây, Rc::clone(&a) tăng số lượng tham chiếu thay vì sao chép sâu dữ liệu. Bây giờ a, bc đều chia sẻ quyền sở hữu.

📊 Theo Dõi Số Lượng Tham Chiếu

Chúng ta có thể quan sát cách số lượng tham chiếu thay đổi với Rc::strong_count:

rust Copy
use std::rc::Rc;

enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    println!("count after creating a = {}", Rc::strong_count(&a));
    let b = Cons(3, Rc::clone(&a));
    println!("count after creating b = {}", Rc::strong_count(&a));
    {
        let c = Cons(4, Rc::clone(&a));
        println!("count after creating c = {}", Rc::strong_count(&a));
    }
    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

Kết Quả:

Copy
count after creating a = 1
count after creating b = 2
count after creating c = 3
count after c goes out of scope = 2

Số lượng tham chiếu tăng lên với mỗi lần Rc::clone và giảm khi một tham chiếu ra khỏi phạm vi. Khi nó cuối cùng đạt 0, dữ liệu sẽ được giải phóng.

🚫 Tại Sao Rc Chỉ Cho Phép Tham Chiếu Bất Biến

Rc<T> cho phép bạn chia sẻ quyền sở hữu thông qua tham chiếu bất biến. Nếu nhiều chủ sở hữu cũng có thể thay đổi dữ liệu, các quy tắc mượn của Rust sẽ bị vi phạm (ví dụ: nhiều mượn có thể cùng lúc).

Nhưng đôi khi, chúng ta cần quyền truy cập chia sẻ có thể thay đổi. Đó là nơi mà mẫu biến đổi nội bộ xuất hiện, sử dụng RefCell<T> kết hợp với Rc<T>. Tôi sẽ khám phá điều này trong buổi học tiếp theo.

🧠 Tóm Tắt

  • Rc<T> cho phép sở hữu nhiều thông qua đếm tham chiếu.
  • Sao chép với Rc::clone tăng số đếm thay vì sao chép sâu.
  • Khi tham chiếu cuối cùng bị xóa, dữ liệu sẽ được giải phóng.
  • Tốt nhất cho các tình huống đơn luồng nơi cần sở hữu chia sẻ.
  • Để thay đổi, kết hợp với RefCell<T> (sẽ đến trong phần tiếp theo!).

🚀 Như vậy là đã kết thúc Ngày 30 của #100DaysOfRust! Hôm nay tôi đã học cách Rc<T> cung cấp sở hữu chia sẻ và dọn dẹp an toàn trong Rust.

Ngày mai: Biến Đổi Nội Bộ với RefCell.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào