本文介绍了取消引用指向String的原始指针和指向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会发生这种情况?为什么抱怨移动"?

解决方案

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

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

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

之所以这样做,是因为您正尝试将所有权移出unsafe块.只要您对此不关心,就需要在unsafe块中包含"move",这样编译器就可以让您脚踏实地.这样,如果您对代码进行重组以使其不移至unsafe块的外部,则代码将编译:

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

它在操场上运行. >

但是,在您的问题评论中再次重申Shepmaster的观点……如果"move"一词对您来说听起来很陌生,那么您不应该首先使用原始指针/unsafe块,而应该使用head返回到Rust的可用文档以理解该概念.因为它是核心.

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);
}

The above code fails with the error:

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

Why does it happen for String and not for i32? Why is it complaining of a "move"?

解决方案

The basic integral types (and in fact, many other types) in Rust implement the Copy trait. They have "copy semantics", not "move semantics". There is no change of ownership here... you're copying out the value. String does not implement the Copy trait and therefore this binding has "move semantics".

This is not unique to raw pointers nor does it have anything to do with their mutability. This example shows this can happen with immutable references:

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

It does this because you're attempting to move ownership out of the unsafe block. As long as you're care-free about this then you need to contain the "move" within the unsafe block so the compiler just lets you shoot yourself in the foot. As such, if you restructure your code so as to not move outside of the unsafe block, the code will compile:

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

Here it is running in the playground.

To re-iterate Shepmaster's point in the comment on your question though... if the term "move" sounds foreign to you then you should not be using raw pointers/unsafe blocks in the first place and should instead head back to the available documentation for Rust to understand the concept.. as it is a core one.

这篇关于取消引用指向String的原始指针和指向i32的原始指针之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 06:19