[Rust] Tìm hiểu về CoW (Copy on Write) trong Rust - Derive Clone
Hôm nay chúng ta sẽ tìm hiểu một thuật ngữ Copy on write
trong Rust. Bạn có thể thấy thỉnh thoảng chúng ta hay sử dụng #[derive(Clone)]
tại mỗi struct
Đây là một trong những hình thức của thuật ngữ này trong Rust
ĐỊNH NGHĨA
Như bạn đã biết thì trong Rust khi thực hiện một phép gán, ta mặc định là move
quyền sở hữu ownership
sang đối tượng khác. Điều này là một trong những điểm rất khác so với ngôn ngữ khác mà mặc định sẽ là copy
.
Copy on write
là một kiểu thiết kế nơi mà dữ liệu gốc sẽ không bao giờ được thay đổi. Bất kỳ khi nào dữ liệu cần được thay đổi, nó sẽ được copy tới một nơi mới, thay đổi giá trị và sau đó trả về một tham chiếu tới bản copy dữ liệu này.
Ví dụ, với copy on write
một mảng, thêm một phần tử sẽ trở về một mảng mới với tất cả phần tử củ và thêm một thành phần mới, và bỏ mảng cũ đi.
Trong Rust, chúng ta sử dụng #[derive(Clone)]
cho thiết kế dạng này. Ngoài ra chúng ta có thể sử dụng một số kiểu dưới đây để thực hiện bằng cách thủ cộng
Trong Rust cung cấp mấy cách để
Rc
vớiArc
: 2 kiểu contrỏ thông minh cung cấp nguyên lýclone on write
với phương thứcmake_mut()
.Rc
is phiên bản cho single-threaded, Arc là phiên bản cho thread safe - sử dụng trong đa luồng- Enum
Cow
pub enum Cow<'a, B> where
B: 'a + ToOwned + ?Sized, {
Borrowed(&'a B),
Owned(<B as ToOwned>::Owned),
}
Trong enum này chúng ta có 2 giá trị:
Borrowed(&'a B)
: Hoặc dữ liệu được được mượn- Dữ liệu là kiểu
Owned
với kiểu B là
Để trigger sang Borrowed
sử dụng hàm to_mut()
THỰC HÀNH
#[derive(Clone)]
struct ListItem<T>
where
T: Clone,
{
data: Box<T>,
next: Option<Box<ListItem<T>>>,
}
#[derive(Clone)]
struct SinglyLinkedList<'a, T>
where
T: Clone,
{
head: Cow<'a, ListItem<T>>,
}
impl<T> ListItem<T>
where
T: Clone,
{
fn new(data: T) -> Self {
ListItem {
data: Box::new(data),
next: None,
}
}
fn next(&self) -> Option<&Self> {
if let Some(next) = &self.next {
Some(&*next)
} else {
None
}
}
fn mut_tail(&mut self) -> &mut Self {
if self.next.is_some() {
self.next.as_mut().unwrap().mut_tail()
} else {
self
}
}
fn data(&self) -> &T {
self.data.as_ref()
}
}
impl<'a, T> SinglyLinkedList<'a, T>
where
T: Clone,
{
fn new(data: T) -> Self {
SinglyLinkedList {
head: Cow::Owned(ListItem::new(data)),
}
}
fn append(&self, data: T) -> Self {
let mut new_list = self.clone();
let mut tail = new_list.head.to_mut().mut_tail();
tail.next = Some(Box::new(ListItem::new(data)));
new_list
}
fn head(&self) -> &ListItem<T> {}
}
Giải thích:
- Đầu tiên chúng ta khởi con trỏ
head
bởiCow::Owned(ListItem::new(data))
- Để có thể
copy on write
sử dụng hàmto_mut()
let mut tail = new_list.head.to_mut().mut_tail();
Have fun!