什么时候将数据放到堆
认识所有权, 生命周期与引用有效性, 智能指针 这三章是相关联的,所有权和生命周期确保数据的有效性,智能指针数据存放在堆上,指针在栈上。
书中建议
- 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
- 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
- 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候
个人理解如果是用户自定义结构体数据数据较大或者在运行时才能确定大小的数据,多个不同作用域需要共享数据时建议放在堆中。Vec
中的数据就是放在堆中。
使用场景
使用Rust
开发一个小工具时,发现经常有调用clone
方法的场景。在读取文件数据解析创建了一个结构体,然后放到一个Vec
中,在某个地方需要获取一些数据修改一些值,然后保持到另一个Vec
中。这时在Vec
中取出了值修改数据,clone
一份保存,虽然到了需求。但是我想的是两个Vec
都是同一份数据,只是两个Vec
数量不一样,这时就需要将对象保持到堆中了。
// 场景 多个 C 对象需要共享 A, B 数据,对A需要有修改权限
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct A {
name: String,
}
impl Drop for A {
fn drop(&mut self) {
println!("A drop: {}", self.name);
}
}
impl Drop for B {
fn drop(&mut self) {
println!("B drop: {}", self.name);
}
}
#[derive(Debug)]
struct B {
name: String,
}
#[derive(Debug)]
struct C {
list_a: Vec<Rc<RefCell<A>>>,
list_b: Vec<Rc<B>>,
}
#[test]
fn test_rc() {
let mut c = C {
list_a: Vec::new(),
list_b: Vec::new(),
};
let a = Rc::new(RefCell::new(A {
name: String::from("zhang"),
}));
let b = Rc::new(B {
name: String::from("wu"),
});
println!("a ptr: {:p}", a);
println!("b ptr: {:p}", b);
c.list_a.push(a);
c.list_b.push(b);
f2(&c);
c.list_b.push(Rc::new(B {
name: String::from("li"),
}));
println!("{:?}", c);
}
fn f2(c: &C) {
let mut c2 = C {
list_a: Vec::new(),
list_b: Vec::new(),
};
for c1a in c.list_a.iter() {
println!("a ptr: {:p}", *c1a);
let mut a = (*c1a).borrow_mut();
a.name = String::from("我改了");
c2.list_a.push(Rc::clone(c1a));
}
for c1b in c.list_b.iter() {
println!("b ptr: {:p}", *c1b);
c2.list_b.push(Rc::clone(c1b));
}
println!("{:?}", c2);
}
上面代码两个 C
都指向了堆上的A
和B
,在f2
中修改C
中的A
数据,并将指针放入了第二个C
中。在代码的运行结果可以发现A
和B
都没有clone
的动作,两个C
对象都是指向的同一份数据。这里的数据不支持多线共享,需要在多线程下共享数据需要使用到Mutex<T>
和Arc<T>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。