Function std::ptr::read

1.0.0 (const: 1.71.0) · source ·
pub const unsafe fn read<T>(src: *const T) -> T
Expand description

src 读取值而不移动它。这将使 src 中的内存保持不变。

Safety

如果违反以下任一条件,则行为是未定义的:

  • src 必须是 有效的 才能读取。

  • src 必须正确对齐。如果不是这种情况,请使用 read_unaligned

  • src 必须指向 T 类型的正确初始化值。

请注意,即使 T 的大小为 0,指针也必须非空且正确对齐。

Examples

基本用法:

let x = 12;
let y = &x as *const i32;

unsafe {
    assert_eq!(std::ptr::read(y), 12);
}
Run

手动实现 mem::swap

use std::ptr;

fn swap<T>(a: &mut T, b: &mut T) {
    unsafe {
        // 在 `tmp` 中的 `a` 处创建值的按位副本。
        let tmp = ptr::read(a);

        // 此时退出 (通过显式返回或调用 panics 的函数) 将导致 `tmp` 中的值被丢弃,而 `a` 仍引用相同的值。
        // 如果 `T` 不是 `Copy`,则可能触发未定义的行为。

        // 在 `a` 中的 `b` 处创建值的按位副本。
        // 这是安全的,因为可变引用不能使用别名。
        ptr::copy_nonoverlapping(b, a, 1);

        // 如上所述,退出此处可能会触发未定义的行为,因为 `a` 和 `b` 引用了相同的值。

        // 将 `tmp` 移至 `b`。
        ptr::write(b, tmp);

        // `tmp` 已移动 (`write` 对其第二个参数的所有权),因此这里没有隐含地丢弃任何东西。
    }
}

let mut foo = "foo".to_owned();
let mut bar = "bar".to_owned();

swap(&mut foo, &mut bar);

assert_eq!(foo, "bar");
assert_eq!(bar, "foo");
Run

归还值的所有权

read 创建 T 的按位副本,无论 T 是否为 Copy。 如果 T 不是 Copy,则同时使用返回的值和 *src 的值可能会违反内存安全性。 请注意,将分配给 *src 视为一种用途,因为它将尝试丢弃 *src 处的值。

write() 可用于覆盖数据,而不会导致数据被丢弃。

use std::ptr;

let mut s = String::from("foo");
unsafe {
    // `s2` 现在指向与 `s` 相同的底层内存。
    let mut s2: String = ptr::read(&s);

    assert_eq!(s2, "foo");

    // 分配给 `s2` 会导致其原始值被丢弃。
    // 除此之外,由于已释放底层内存,因此不能再使用 `s`。
    s2 = String::default();
    assert_eq!(s2, "");

    // 分配给 `s` 将导致旧值再次被丢弃,从而导致未定义的行为。
    // s = String::from("bar");  // 错误

    // `ptr::write` 可用于覆盖一个值而无需丢弃它。
    ptr::write(&mut s, String::from("bar"));
}

assert_eq!(s, "bar");
Run