今天,我們來學習 Rust 的智慧指標和內部可變性概念。這些進階特性讓我們能更靈活地管理記憶體和共享資料,同時保持 Rust 的安全性保證。
智慧指標是一種資料結構,不僅作為指標使用,還具有額外的元資料和功能。Rust 中最常用的智慧指標包括 Box<T>
、Rc<T>
和 Arc<T>
。
Box<T>
是最簡單的智慧指標,它允許我們將資料存儲在堆積上而不是堆疊上。
fn main() {
// 在堆積上分配一個整數
let x = Box::new(5);
println!("x = {}", x);
// 遞迴型別
#[derive(Debug)]
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("list = {:?}", list);
}
Rc<T>
(參考計數)允許資料有多個所有者。它適用於需要在程式的多個部分共享資料的情況。
use std::rc::Rc;
fn main() {
let x = Rc::new(5);
let y = Rc::clone(&x);
let z = Rc::clone(&x);
println!("參考計數: {}", Rc::strong_count(&x));
println!("x = {}, y = {}, z = {}", x, y, z);
}
Arc<T>
(原子參考計數)是 Rc<T>
的執行緒安全版本,適用於多執行緒環境。
use std::sync::Arc;
use std::thread;
fn main() {
let x = Arc::new(5);
let mut handles = vec![];
for _ in 0..3 {
let x = Arc::clone(&x);
let handle = thread::spawn(move || {
println!("x = {} in thread {:?}", x, thread::current().id());
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
內部可變性是 Rust 中一個重要的概念,它允許你在擁有不可變參考時修改資料。主要通過 RefCell<T>
和 Mutex<T>
實現。
RefCell<T>
提供了執行期借用檢查的內部可變性。
use std::cell::RefCell;
fn main() {
let x = RefCell::new(5);
{
let mut borrowed = x.borrow_mut();
*borrowed += 1;
}
println!("x = {:?}", x);
let borrowed = x.borrow();
println!("借用的值 = {}", *borrowed);
}
Mutex<T>
提供了執行緒安全的內部可變性。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("計數結果:{}", *counter.lock().unwrap());
}
我們可以結合使用這些概念來建立更複雜的資料結構。
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Node {
value: i32,
children: RefCell<Vec<Rc<Node>>>,
}
fn main() {
let root = Rc::new(Node {
value: 1,
children: RefCell::new(vec![]),
});
let child1 = Rc::new(Node {
value: 2,
children: RefCell::new(vec![]),
});
let child2 = Rc::new(Node {
value: 3,
children: RefCell::new(vec![]),
});
// 動態新增子節點
root.children.borrow_mut().push(Rc::clone(&child1));
root.children.borrow_mut().push(Rc::clone(&child2));
// 列印樹狀結構
fn print_tree(node: &Node, indent: String) {
println!("{}Node({})", indent, node.value);
for child in node.children.borrow().iter() {
print_tree(child, format!("{} ", indent));
}
}
print_tree(&root, String::new());
}
讓我們使用智慧指標和內部可變性來實作一個簡單的緩存系統:
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;
use std::cell::RefCell;
struct Cache<K, V> {
map: RefCell<HashMap<K, Rc<V>>>,
}
impl<K: Hash + Eq, V> Cache<K, V> {
fn new() -> Self {
Cache {
map: RefCell::new(HashMap::new()),
}
}
fn get(&self, key: &K) -> Option<Rc<V>> {
self.map.borrow().get(key).cloned()
}
fn insert(&self, key: K, value: V) {
self.map.borrow_mut().insert(key, Rc::new(value));
}
}
fn main() {
let cache = Cache::new();
cache.insert("key1", "value1");
cache.insert("key2", "value2");
match cache.get(&"key1") {
Some(value) => println!("找到 key1:{}", value),
None => println!("未找到 key1"),
}
match cache.get(&"key3") {
Some(value) => println!("找到 key3:{}", value),
None => println!("未找到 key3"),
}
// 展示共享所有權
let value1 = cache.get(&"key1").unwrap();
let value1_clone = Rc::clone(&value1);
println!("原始值:{}, 複製值:{}", value1, value1_clone);
}
明天,我們將探討 Rust 的進階特性,包括不安全 Rust、進階特徵和型別系統的更多細節。