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

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

本文关键字:什么 区别 引用 Rust 指针      更新时间:2023-10-16

在Rust 中,指针*和引用&共享相同的表示形式(它们都表示一段数据的内存地址(。

但是,编写代码时的实际区别是什么?

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

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

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

引用在类型和生存期内是泛型的。共享引用以长格式编写&'a T(其中'aT是参数(。在许多情况下,可以省略生存期参数。编译器使用生存期参数来确保引用的生存期不会超过借用的有效时间。

指针没有生存期参数。因此,编译器无法检查特定指针是否有效使用。这就是为什么取消引用指针被认为是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

静音指针没有这样的保证。

引用不能为 null(与C++引用非常相似(。指针可以为空。

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

如果你有一个*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 中没有->运算符。

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