Rust 中的指针和引用有什么区别?

What are the differences between a pointer and a reference in Rust?

Rust中的指针*和引用&是同一个表示(都是表示一段数据的内存地址)

虽然在编写代码时有什么实际区别?

将 C++ 代码移植到 Rust 时,它们是否可以安全地替换(C++ 指针 --> Rust 指针,C++ 引用 --> Rust 引用)?

Rust 引用只是一个指针,但编译器赋予它们借用语义。当您对对象进行不可变引用时,编译器会确保在派生引用消失之前您无法修改该对象。

尽可能使用引用,必须使用指针。如果您不执行超出编译器可验证范围的 FFI 或内存管理,则不需要使用指针。

引用和指针都存在两种变体。有共享引用 & 和可变引用 &mut。有 const 指针 *const 和 mut 指针 *mut(映射到 C 中的 const 和非常量指针)。然而,引用的语义与指针的语义完全不同。

引用在一个类型和整个生命周期内都是通用的。共享引用以长格式写成 &'a T(其中 'aT 是参数)。 lifetime参数在很多情况下可以是omitted。编译器使用生命周期参数来确保引用的寿命不会超过借用的有效期。

指针没有生命周期参数。因此,编译器无法检查特定指针是否有效。这就是为什么取消引用指针被认为是 unsafe.

当您创建对象的共享引用时,冻结对象(即对象在共享引用存在时变得不可变),除非对象使用某种形式的内部可变性(例如使用 CellRefCellMutexRwLock)。但是,当您有一个指向对象的 const 指针时,该对象可能仍会在指针处于活动状态时发生变化。

当您有一个对象的可变引用时,您保证可以通过该引用独占访问该对象。访问该对象的任何其他方式要么暂时禁用,要么无法实现。例如:

let mut x = 0;
{
    let y = &mut x;
    let z = &mut x; // ERROR: x is already borrowed mutably
    *y = 1; // OK
    x = 2; // ERROR: x is borrowed
}
x = 3; // OK, y went out of scope

Mut 指针没有这样的保证。

引用不能为空(很像 C++ 引用)。指针可以为空。

指针可以包含适合 usize 的任何数值。初始化一个指针不是unsafe;只是取消引用它。另一方面,产生无效引用被视为 undefined behavior,即使您从未取消引用它也是如此。

如果您有 *const T,您可以使用 as 将其自由转换为 *const U*mut T。你不能用引用来做到这一点。但是,您可以使用 as 转换对指针的引用,并且可以通过取消引用指针(同样是 unsafe)将指针“升级”为引用,然后借用该位置使用&&mut。例如:

use std::ffi::OsStr;
use std::path::Path;

pub fn os_str_to_path(s: &OsStr) -> &Path {
    unsafe { &*(s as *const OsStr as *const Path) }
}

在 C++ 中,引用是“自动解除引用的指针”。在 Rust 中,您通常仍然需要显式取消引用引用。使用 . 运算符时例外:如果左侧是引用,编译器将自动取消引用它(必要时递归!)。但是,指针不会自动解除引用。这意味着如果你想解引用和访问一个字段或方法,你需要写成(*pointer).field(*pointer).method()。 Rust 中没有 -> 运算符。