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

sou*_*ics 1 pointers ownership-semantics rust borrow-checker

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);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码失败并出现错误:

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);
}
Run Code Online (Sandbox Code Playgroud)

为什么它发生为String而不是为i32?为什么它抱怨“移动”?

Sim*_*ead 5

为什么它发生为String而不是为i32

Rust 中的基本整数类型(实际上还有许多其他类型)实现Copytrait。它们具有“复制语义”,而不是“移动语义”。这里没有所有权变更……您正在复制价值。String 没有实现Copy特点,因此这种结合具有“移动语义”。

这不是原始指针独有的,也与它们的可变性没有任何关系。这个例子表明这可能发生在不可变引用中:

fn func(s: &String, a: &i32) {
    let _x = *s;
    let _x = *a;
}
Run Code Online (Sandbox Code Playgroud)

为什么它抱怨“移动”?

这样做是因为您试图将所有权移出该unsafe块。只要你不关心这个,那么你就需要在unsafe块中包含“移动”,这样编译器就会让你用脚射击自己。因此,如果您重构代码以便不移动unsafe之外,代码将编译:

unsafe {
    println!("{}", *s);
}
Run Code Online (Sandbox Code Playgroud)

它正在操场上奔跑

不过,要重申 Shepmaster 在对您的问题的评论中的观点……如果“移动”一词对您来说听起来很陌生,那么您首先不应使用原始指针/unsafe块,而应返回可用的文档Rust 来理解这个概念......因为它是一个核心概念。

  • @soupybionics `println!` 不拥有所有权 [(实际上,它会自动引用其参数)](/sf/ask/2131527961/ ),但该值必须从块内部移动到外部。[这是一个没有任何 `unsafe` 的相同问题的例子。](https://play.rust-lang.org/?gist=4cf04e1a7aadb054bcc3b6ba64aa03fe&version=stable) `{}` 块通过使值 `* s` 变成一个临时的,就像 `unsafe` 块一样。`println!("{}", *s);` 会起作用。(但 `println!("{}", s)` 也是如此。) (2认同)