1
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?为什么抱怨“搬家”?

4

1 回答 1

5

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

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

这不是原始指针所独有的,也与它们的可变性无关。此示例显示不可变引用可能会发生这种情况:

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

为什么抱怨“搬家”?

这样做是因为您试图将所有权移出unsafe区块。只要您对此不关心,那么您就需要在unsafe块中包含“移动”,这样编译器就可以让您在脚下射击自己。因此,如果您重组代码以免移出块外unsafe则代码将编译:

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

它在操场上运行

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

于 2017-12-19T04:10:22.427 回答