问题描述
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的原始指针之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!