取消引用指向 String 的原始指针和指向 i32 的原始指针之间有什么区别?

What is the difference between dereferencing a raw pointer to a String and a raw pointer to an i32?

fn func(s: *mut String, a: *mut i32) -> usize {
    println!("{}", unsafe { *s });
    println!("{}", unsafe { *a });

    unsafe { (*s).len() }
}

fn main() {
    let mut s = String::from("hello");
    let mut a = 10;

    func(&mut s, &mut a);
}

以上代码失败并出现错误:

error[E0507]: cannot move out of dereference of raw pointer
 --> src/main.rs:2:29
  |
2 |     println!("{}", unsafe { *s });
  |                             ^^ cannot move out of dereference of raw pointer

为什么 String 而不是 i32?为什么它抱怨 "move"?

Why does it happen for String and not for i32?

Rust 中的基本整数类型(实际上还有许多其他类型)实现 the Copy trait。他们有 "copy semantics",而不是 "move semantics"。这里没有所有权的变化......你正在复制价值。 String 未实现 Copy 特征,因此此绑定具有 "move semantics"。

这不是原始指针独有的,也与它们的可变性无关。 This example shows 这可能发生在不可变引用中:

fn func(s: &String, a: &i32) {
    let _x = *s;
    let _x = *a;
}

Why is it complaining of a "move"?

它这样做是因为您正试图将所有权移出 unsafe 块。只要您对此无所谓,就需要将 "move" 包含在 unsafe 块中,这样编译器就会让您搬起石头砸自己的脚。因此,如果您重组代码以便 不移到 unsafe 块的 之外,代码将编译:

unsafe {
    println!("{}", *s);
}

Here it is running in the playground.

虽然要重申 Shepmaster 在对您的问题的评论中的观点...如果术语 "move" 对您来说听起来很陌生,那么您不应该在中使用原始指针/unsafe 块第一名,应该返回 Rust 的可用文档来理解这个概念。因为它是一个核心概念。