Intelligente Zeiger
Verständnis
Typen, die Deref und Drop implementieren, können als intelligente Zeiger dienen.
Box
Drei typische Einsatzfälle für Box:
- Wenn die Größe eines Typs zur Laufzeit unbekannt ist.
- Wenn Daten groß sind und Kopierkosten beim Übertragen des Besitzes vermieden werden sollen.
- Wenn man einen Wert besitzen, aber nur einen bestimmten Trait beachten möchte.
recursive type Rust ,
// 以下代码会编译失败
enum List {
Cons(i32, List),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}

Mit Box kann der Compiler die Speichergröße des Typs ableiten.
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

Deref und Drop
,, Rust ( Deref trait deref )
Deref coercion happens automatically when we pass a reference to a particular type’s value as an argument to a function or method that doesn’t match the parameter type in the function or method definition.
Drop trait drop , value goes out of scope (FILO)
drop
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
// 先调用 d 的 drop 方法,再调用 c 的 drop 方法
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
// drop 不允许被主动调用,以下代码会编译失败
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
c.drop();
println!("CustomSmartPointer dropped before the end of main.");
}
// 可以通过 std::mem:drop 间接触发 drop 的调用
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
Rc
Referenzzählung, geeignet zur Implementierung von Graphen.
// 基础写法
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a)); // 使用 clone 实现浅拷贝
let c = Cons(4, Rc::clone(&a));
}
// 使用 strong_count 获取当前变量被引用的数量
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));
}
RefCell
Box RefCell ,RefCell runtime immutable or mutable borrows checked
, panic
Box<T>,Rc<T>, orRefCell<T>:
Rc<T>owner,Box<T>RefCell<T>owner
Rc<T>enables multiple owners of the same data;Box<T>andRefCell<T>have single owners.
Box<T>immutable or mutable borrows checked;Rc<T>immutable borrows checked;RefCell<T>immutable or mutable borrows checked
Box<T>allows immutable or mutable borrows checked at compile time;Rc<T>allows only immutable borrows checked at compile time;RefCell<T>allows immutable or mutable borrows checked at runtime.
RefCell<T>mutable borrows checked,RefCell<T>,RefCell<T>Because
RefCell<T>allows mutable borrows checked at runtime, you can mutate the value inside theRefCell<T>even when theRefCell<T>is immutable.
// 基础写法 - 和 Rc 配合使用
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}", a);
println!("b after = {:?}", b);
println!("c after = {:?}", c);
}
Weak
Strong<T>
Rc::downgrade, Weak<T> , weak_count 1
strong_count 0 ,weak_count 0 , ref
upgrade ( Option )
// 可以通过该例直观感受弱引用、强引用使用上的区别
use std::cell::RefCell;
use std::rc::{Rc, Weak};
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
{
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!(
"branch strong = {}, weak = {}",
Rc::strong_count(&branch),
Rc::weak_count(&branch),
);
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
leaf strong = 1, weak = 0
branch strong = 1, weak = 1
leaf strong = 2, weak = 0
leaf parent = None
leaf strong = 1, weak = 0
Quelle
…
Intelligente Zeiger besitzen zusätzliche Metadaten und Fähigkeiten gegenüber gewöhnlichen Referenzen. Box<T> speichert Daten auf dem Heap, Deref ermöglicht die Verwendung wie eine Referenz, und Drop bestimmt, was beim Verlassen des Gültigkeitsbereichs geschieht. Rc<T> zählt gemeinsame Besitzer; RefCell<T> verschiebt die Prüfung von Borrowing-Regeln von der Kompilierzeit in die Laufzeit.