- 引用
&
reference - 解引用
*
dereference
int val = 1234;
int *p = &val;
printf("p = %p\n", p);
printf("*p = %d\n", *p);
// val = 666;
*p = 888; // 可变性
printf("*p = %d\n", *p);
p = 0x7ff7ba3052c4 *p = 1234 *p = 888
&T
引用&mut T
可变引用
let mut val = 123;
{
let mut p = &mut val;
println!("{:p}", p);
println!("{}", p);
println!("{}", *p);
*p = 222;
}
val = 444;
println!("{}", val);
0x7ff7b778abd4 123 123 444
- 智能指针 smart pointer
- 在堆上分配内存 | link
malloc(...)
Box<T>
是 Rust 中最常见的智能指针- &v
- *v
- 它是简单的封装,除了将值存储在堆上外,并没有其它性能上的损耗
- 使用场景:
- 特意的将数据分配在堆上
- 数据较大时,又不想在转移所有权时进行数据拷贝
- 类型的大小在编译期无法确定,但是我们又需要固定大小的类型时
enum List { Nil, Cons(i32, Box<List>), }
- Trait Object,用于说明对象实现了一个特征,而不是某个特定的类型
fn make_clousre() -> Box<dyn Fn(i32) -> i32> { }
简单实现 MyBox
use std::ops::Deref; #[allow(unused_variables)] #[allow(dead_code)] struct MyBox(i32); impl Deref for MyBox { type Target = i32; fn deref(&self) -> &i32 { println!("deref in MyBox"); &self.0 } } impl Drop for MyBox { fn drop(&mut self) { println!("drop in MyBox"); } }
- 引用计数 | link
- 使用
.clone()
获取只读引用use std::rc::Rc; let v1 = Box::new(123); println!("Box v1 = {:p}", v1); println!("Box v1.clone = {:p}", v1.clone()); println!("Box v1.clone = {:p}", v1.clone()); let v2 = Rc::new(123); println!("Rc v2 = {:p}", v2); println!("Rc v2.clone = {:p}", v2.clone()); println!("Rc v2.clone = {:p}", v2.clone());
Box v1 = 0x600002f20000 Box v1.clone = 0x600002f2c050 Box v1.clone = 0x600002f2c050 Rc v2 = 0x600002d28bb0 Rc v2.clone = 0x600002d28bb0 Rc v2.clone = 0x600002d28bb0
- 优点是可以放到多处,可以共享所有权
use std::rc::Rc; #[derive(Debug)] struct Foo { v: Box<i32>, } #[derive(Debug)] struct Bar { v: Rc<i32>, } let v1 = Box::new(123); let f1 = Foo { v: v1}; // 没有所有权,会报错 // let f2 = Foo { v: v1 }; let v2 = Rc::new(222); let b1 = Bar { v: v2.clone() }; let b2 = Bar { v: v2 };
error: Could not compile `cargoXIpimx`.
- 当 referenced count == 1 时可以修改
let mut v2 = Rc::new(123); let r1 = Rc::get_mut(&mut v2); println!("r1 = {:?}", r1);
- 弱引用 Weak
- referenced counter
- strong referenced counter
- weak referenced counter
use std::cell::{Cell, RefCell};
#[allow(unused_variables)]
#[allow(dead_code)]
#[derive(Debug)]
struct Foo {
x: Cell<i32>,
y: RefCell<u32>,
}
fn main() {
let foo1 = Foo {
x: Cell::new(123),
y: RefCell::new(345),
};
println!("foo1 = {:#?}", foo1);
foo1.x.set(666);
println!("foo1 = {:#?}", foo1);
println!("foo1.x = {:#?}", foo1.x.get());
}
- 内部可变性
- get() 获取值
- set() 设置值
- T 只能设置 Copy 类型
- 运行时动态检测,可能会造成 panic
- T 可以是任何类型
- 通过 borrow() / borrow_new() 进行操作
let v1 = RefCell::new(vec![1]);
{
let mut inner = v1.borrow_mut();
inner.push(2);
}
println!("v1 = {:?}", v1.borrow());
let v1 = RefCell::new(vec![1]);
let mut inner = v1.borrow_mut();
inner.push(2);
println!("v1 = {:?}", v1.borrow());
let mut inner2 = v1.borrow();
上述代码会 panic
thread 'main' panicked at src/main.rs:17:30: already mutably borrowed: BorrowError
struct Foo {
v: Rc<RefCell<Vec<i32>>>,
u: Rc<Vec<i32>>,
}
- 和 c 语言类似的裸指针
- 很少使用,基本上出现场景就是标准库
- unsafe