Rust中的指针解引用

9
我对以下问题感到相当困惑。如果我理解正确,
let x = &42;

被内部扩展为

let x_value = 42;
let x = &x;

我记得在Rust书中看到过这个内容,但是我找不到相关的引用。

我的问题与以下代码有关:

let x = 42;
let rx = &x;
let px = rx as *const i32 as *mut i32;
unsafe {
  *px = 0;
}
println!("{}", x);

按预期,这会打印 0。然而,如果我写成:
let rx = &42;
let px = rx as *const i32 as *mut i32;
unsafe {
  println!("Deref");
  *px = 0;
}
println!("{}", x);

程序在打印出“Deref”后终止。显然,当对“px”进行解引用时出现了问题。我猜测我的第一个关于“let x = &42”被内部扩展的评估是错误的。
2个回答

12
您正在调用未定义的行为。根据 Rust参考手册

12.3 被视为未定义的行为

以下是禁止在所有Rust代码中使用的行为列表,包括不安全块和不安全函数中使用的内容。[...]

  • 修改非可变数据(即通过共享引用访问的数据或由let绑定拥有的数据),除非该数据包含在UnsafeCell<U>中。

由于您正在修改非可变数据,因此您正在调用未定义的行为。在第一个版本中它能够正常工作仅仅是(不好的)运气。


1
我查看了 UnsafeCell<T> 的实现并想要尝试使用原始指针。我忽略了一个重要的部分,即 #[lang = "unsafe_cell"] 属性。谢谢。 - jan

1
let x = 42;
let rx = &x;

在这里,您可以在堆栈上创建一个新变量,并写入来自程序代码的值42。 创建引用时,它引用堆栈上的此值。 当您通过*px = 0更改该值时,您可以访问堆栈上的值并更改它。

在第二种情况下

let rx = &42;

你直接创建一个引用,指向存储代码(指令和其他数据)的内存部分中存储的值。而且这个内存部分是不可变的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接