智能指针¶
BOX\<T>¶
能够在堆上存储数据
Box使用¶
fn main() {
let b = Box::new(5);
println!("b = {}",b)
}
Rust需要在编译时确定类型占用的内存空间, 通常的类型不能处理递归类型(无法确定将要占用的内存空间)。 而由于Box是指针,所以它能处理递归类型
处理递归类型¶
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1,Cons(2,Cons(3,Nil)));
}
enum List { // 报错
Cons(i32,List),
Nil,
}
error[E0072]: recursive type `List` has infinite size
--> src/main.rs:8:1
|
8 | enum List {
| ^^^^^^^^^
9 | Cons(i32,List),
| ---- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
9 | Cons(i32,Box<List>),
| ++++ +
修改后:
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1,
Box::new(Cons(2,
Box::new(Cons(3,
Box::new(Nil))))));
}
enum List {
Cons(i32,Box<List>),
Nil,
}
解引用
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
实现自己的Box类型
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x:T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> { // 实现deref
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Drop Trait¶
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("{}" , self.data)
}
}
fn main() {
let c = CustomSmartPointer { data: String::from("test") };
// c.drop(); // not allowed
let d = CustomSmartPointer { data: String::from("test2") };
drop(d);
}
test2
test
类似于C++中的析构函数
Rust不允许手动调用drop方法 但可以调用std::mem::drop
Rc¶
引用计数的智能指针(只能用于单线程环境)
Rc<\T>
共享只读数据
use std::rc::Rc;
use crate::List::{Cons,Nil};
enum List {
Cons(i32,Rc<List>),
Nil
}
fn main() {
let a = Rc::new(Cons(5,Rc::new(Cons(10,Rc::new(Nil)))));
println!("count = {}", Rc::strong_count(&a));
a.clone(); // 类型clone 深拷贝 而Rc::clone是浅拷贝 只增加引用计数
println!("count = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a)); // a的引用计数 + 1
println!("count = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count = {}", Rc::strong_count(&a));
}
println!("count = {}", Rc::strong_count(&a));
}
count = 1
count = 1
count = 2
count = 3
count = 2
RefCell 和 内部可变性¶
Rust中的RefCell<T>
是一个智能指针,它允许您在运行时借用可变或不可变的数据。RefCell<T>
被设计为在运行时检查借用规则,而不是在编译时。
RefCell<T>
的使用通常涉及到两种方法:.borrow()
和.borrow_mut()
。.borrow()
用于获取一个不可变引用,而.borrow_mut()
用于获取一个可变引用。在运行时,RefCell<T>
会跟踪当前的借用情况,并在违反规则时引发运行时错误。
以下是一个简单的示例,展示了如何在RefCell<T>
中存储一个可变的字符串,并进行读取和修改:
use std::cell::RefCell;
fn main() {
let my_string = RefCell::new(String::from("hello"));
let borrowed_string = my_string.borrow();
println!("{}", borrowed_string);
let mut mutable_string = my_string.borrow_mut();
mutable_string.push_str(", world!");
println!("{}", mutable_string);
}
在此示例中,我们首先创建了一个名为my_string
的RefCell<T>
,其中包含了一个可变的字符串。然后,我们使用.borrow()
方法获取了一个不可变的引用,并打印了字符串。接下来,我们使用.borrow_mut()
方法获取了一个可变的引用,并将其修改为带有新值的字符串,然后再次打印出来。
另一个示例是在循环中使用RefCell<T>
来构建一个树形结构。在这个例子中,我们使用RefCell<T>
来在节点之间传递可变引用:
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
left: Option<Box<Node>>,
right: Option<Box<Node>>,
}
fn main() {
let leaf1 = Node {
value: 1,
left: None,
right: None,
};
let leaf2 = Node {
value: 2,
left: None,
right: None,
};
let node1 = Node {
value: 3,
left: Some(Box::new(leaf1)),
right: Some(Box::new(leaf2)),
};
let leaf3 = Node {
value: 4,
left: None,
right: None,
};
let leaf4 = Node {
value: 5,
left: None,
right: None,
};
let node2 = Node {
value: 6,
left: Some(Box::new(leaf3)),
right: Some(Box::new(leaf4)),
};
let root = Node {
value: 7,
left: Some(Box::new(node1)),
right: Some(Box::new(node2)),
};
let tree = RefCell::new(root);
inorder_traversal(&tree.borrow());
}
fn inorder_traversal(node: &Node) {
if let Some(left) = &node.left {
inorder_traversal(left);
}
println!("{}", node.value);
if let Some(right) = &node.right {
inorder_traversal(right);
}
}
在此示例中,我们构建了一个二叉树,并使用RefCell<T>
来在节点之间传递可变引用。我们还定义了一个名为inorder_traversal()
的函数,该函数使用递归方式遍历二叉树,并按顺序打印出每个节点的值。
use std::{rc::Rc, cell::{RefCell, Ref}};
use crate::List::{Cons,Nil};
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>,Rc<List>),
Nil
}
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(6)), Rc::clone(&a));
let c =Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}",a);
println!("b after = {:?}",b);
println!("c after = {:?}",c);
}
output
a after = Cons(RefCell { value: 15 }, Nil)
b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil))
c after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil))
防止循环引用把Rc<\T>换为Weak<\T>