mem::replace() 函数
传入一个同类型的值, 并与目标值进行交换.
该函数的接口如下:
pub const fn replace<T>(dest: &mut T, src: T) -> T;
可以看到, 目标值 dest 是以可变更引用的形式 &mut T 传入的, 这样的话, 类型 T 必须做到内存对齐.
如果无法满足内存对齐的要求, 可以使用 ptr::replace().
接下来看一个基本的示例程序:
use std::mem;
fn main() {
let mut v = [Box::new(2), Box::new(3), Box::new(4)];
let ret = mem::replace(&mut v[1], Box::new(42));
assert_eq!(*ret, 3);
assert_eq!(*v[1], 42);
let mut v1 = vec![1, 2, 3];
let mut v2 = vec![4, 5];
// 使用语法糖
(v1, v2) = (v2, v1);
v2 = mem::replace(&mut v1, v2);
assert_eq!(v2, vec![4, 5]);
}
replace() 函数的实现
这个函数的内部实现也较简单, 直接看源代码:
use std::ptr;
#[inline]
pub const fn replace<T>(dest: &mut T, src: T) -> T {
// It may be tempting to use `swap` to avoid `unsafe` here. Don't!
// The compiler optimizes the implementation below to two `memcpy`s
// while `swap` would require at least three. See PR#83022 for details.
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
// such that the old value is not duplicated. Nothing is dropped and
// nothing here can panic.
unsafe {
let result = ptr::read(dest);
ptr::write(dest, src);
result
}
}
整个过程有以下几步:
- 先在栈上创建一个临地对象
result - 将目标值
dest的所有字节都拷贝到result; 发生所有权转移, 此时result拥有了dest所指向值的所有权, 但dest并不会被 drop - 将源值
src的所有字节都拷贝到dest; 发生了所有权转移, 此时dest拥有了src所指向值的所有权, 但src并不会被 drop - 最后将
result返回