Rust 类型转换与智能指针
类型转换
转换不具有传递性 就算 类型甲 as 类型乙 as 类型丙
是合法的,也不能说明 类型甲 as 类型丙
是合法的.
对于带有禀赋约束的泛型,以及禀赋对象,隐式类型转换 不会 发生. 必须手动把一个不满足禀赋约束或禀赋对象的类型转换成一个满足的.
From 与 Into
From 与 Into 是两个相关的禀赋。当类型 甲 实现 From 到 类型 乙 后,乙 等于实现了 Into 到 甲.
对复杂类型进行隐式转换就是调用得对应的 from
函数.
解引用
任何实现了 Dref 或 DrefMut
禀赋的类型都可以使用 *
操作符解引用.
虽然名义上是 *
进行的解引用操作,事实上 Rust
会在真正的 *
之前插入一个 dref()
函数的调用,
因此实现的时候需要让函数返回一个能够继续被解引用的类型.
这么做的原因是如果让 dref()
返回一个值,
那么原来的对象就失去了对这个值的所有权了.
鉴于解一个引用就丢所有权这件事情有点奇怪,因此 Rust
要求 dref()
返回另一个能被解引用的对象.
这条解引用的调用链会在对普通的指针和引用解引用后停止. 这些内置的类型有编译器照顾的专门实现.
Rust 在解引用是会自动把智能指针和多层的引用转化成一层引用的形式, 然后再进行解引用操作。这个叫做引用的归一化
静态独占引用可以被隐式解引用为静态共享引用.
智能指针
智能指针是对堆对象的引用,因此可以被称作动态引用. 他们在栈上存放指针信息。信息中保存了对象所在的堆地址. 这样做的好处是对象只在必要的时候显式调用复制方法来复制对象. 平时使用智能指针的时候最多只有复制指针的开销, 无需担心复制对象的开销.
Rust 拥有五种智能指针: Box, Rc, Arc, RefCell, Mutex. 它们都实现了 Dref 和 Drop 两个禀赋,因此可以像普通引用那样解引用, 也不需要操心释放问题.
Box
创建时会将对象转移到堆上,同时给予创建的 Box 对象的所有权. 如果对象原先有主,那么原来的主人将失去所有权.
使用 Box::leak(盒对象)
, 可以拿走 盒对象
的所有权并且强制盒子中的值从内存中泄漏,其生命周期为 static
.
可以用来在运行时创建静态变量。比如把一个 String
类型的对象转换成 &str
类型.
Rc
- 使用引用计数来维护指向对象的 Rc 数量. 当引用计数为零时释放对象.
- 创建时会将对象转移到堆上,同时给予创建的 Rc 对象的所有权. 如果对象原先有主,那么原来的主人将失去所有权.
- 使用
Rc::clone(引用: &Rc<类型>)
创建共享所有权的 Rc. 其实仅仅是将引用计数加上了一而已. - 使用
Rc::downgrade(引用: &Rc<类型>)
创建只能确认. 其实仅仅是将引用计数加上了一而已. - 使用
Rc::strong_count(引用, &Rc<类型>)
获得所有引用 引用 指向的对象的 Rc - 使用
Rc::weak_count(引用, &Rc<类型>)
获得所有引用 引用 指向的对象的 Weak - 解引用出来的对象只读.
- 仅仅用于单线程程序.
Arc
Rc 的多线程版本.
RefCell
- 相比 Cell, 它不用复制对象.
- 仅在运行时检查借用规则,如果违反,程序直接挂掉.
- 创建时会将对象转移到堆上,同时给予创建的 Rc 对象的所有权. 如果对象原先有主,那么原来的主人将失去所有权.
- 使用
borrow
方法返回一个只读的 Ref <类型>. - 使用
borrow_mut
方法返回一个可写的 Ref_Mut <类型>.
使用
Rc<RefCell<类型>>
可以使得对象获得多个静态独占引用.
原理是 Rc 只保证它引用的对象,这里就是 RefCell,
本身只读。创建许多 RefCell 彼此互不干扰,
都可以使用 borrow_mut
创建一个指向对象的 RefMut.
Cell::from_mut
: 该方法将&mut 类型
转换为&Cell<类型>
.Cell::as_slice_of_cells
: 该方法将&Cell<[类型]>
转为&[Cell<类型>]
Mutex
RefCell 的多线程版本.