mem::replace() 函数

传入一个同类型的值, 并与目标值进行交换.

该函数的接口如下:

#![allow(unused)]
fn main() {
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() 函数的实现

这个函数的内部实现也较简单, 直接看源代码:

#![allow(unused)]

fn main() {
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
    }
}
}

整个过程有以下几步:

  1. 先在栈上创建一个临地对象 result
  2. 将目标值 dest 的所有字节都拷贝到 result; 发生所有权转移, 此时 result 拥有了 dest 所指向值的所有权, 但 dest 并不会被 drop
  3. 将源值 src 的所有字节都拷贝到 dest; 发生了所有权转移, 此时 dest 拥有了 src 所指向值的所有权, 但 src 并不会被 drop
  4. 最后将 result 返回