rust - 为什么对原语的引用没有隐式取消引用

标签 rust

禁止对非平凡类型(实现 drop)的隐式取消引用是有意义的。但我很好奇将这种预防措施扩展到原语背后的原因是什么。

由于基元是复制而不是移动的,因此为基元类型提供隐式解引用是否有意义?

是否存在对原始类型的隐式取消引用可能危险的情况?或者这只是 rust 编译器还无法做到的事情?

最佳答案

Rust 有很多操作可以同时处理引用和对象。其中包括比较运算符( x < y&x < &y 相同)、方法调用( (&x).func()x.func() 相同)和某些函数( println!("{}", &x)println!("{}", x) 相同) 。但是,Rust 中只有三种不同的方式可以将引用视为与对象相同。

第一种方法是特征实现。某些特征是为类型 T 实现的,但它们还包括一揽子实现 impl<T> Trait for &T这只是遵循 Trait实现T 。其中一个示例是标准比较运算符,它使用 std::cmp::Ord特征。此特征有一个全面的实现, impl<A> Ord for &A ,其中 just defers to the Ord implementation on A 。这就是为什么您可以比较两个 i32 s (因为 i32 实现 Ord ),并且您可以比较两个 &i32 s (因为 &i32 由于一揽子实现而实现了 Ord ),但您无法比较 i32&i32 (因为它们是不同的类型)。

第二种方式是点运算符 ( . )。当您对值调用方法时,(&3).abs() ,Rust 做了一大堆魔法来自动将类型强制转换为适用于该方法的类型。 The full specification is here ,但重要的是,如果 Rust 没有检测到对引用的有效方法调用,它将尝试隐式取消引用该值。 Rust 甚至递归地执行此操作,这意味着您可以编写 (&&&&&&&&&&&3).abs()并仍然编译它。这就是为什么方法调用可以将引用与对象一起使用。

第三种方式是 std::borrow::Borrow traitBorrow<T>双方都满意T&T ,这意味着某些函数可以声明它们将接受引用或对象。以下代码编译并打印 your number is 3两次:

use std::borrow::Borrow;

fn f<T: Borrow<i32>>(num: T) {
    println!("your number is {}", num.borrow());
}

fn main() {
    f(3);
    f(&3);
}

原因vector[&idx]不会神奇地取消引用该参数是因为 []索引运算符由 std::ops::Index 处理特征,以​​及index该特征的函数仅接受确切的类型。 std::ops::Index::index函数可以更改为使用 Borrow ,但就所有 Rust 开发人员所知,有人可能想要实现一个处理 data[&x] 的数据结构。和data[x]独立地,他们希望促进这一点。

那么为什么 Rust 不隐式地对原始类型进行解引用呢?

Rust 尝试将原始类型与用户提供的类型完全相同:它们没有任何无法在用户提供的类型上重新创建的额外特殊行为。这就是为什么 crate 像 ux可以提供更多“原始”类型,例如 i7 , u4i42 :因为没有什么是基元类型能做而用户定义类型不能做的。

由于我们希望将这种自动取消引用行为扩展到用户提供的类型,因此我们可能会说“好吧,所有 Copy 类型都将具有自动取消引用行为。”问题是像 [u8; 1024*1024*1024*1024] 这样的类型(即 1GB 大小的类型)实现 Copy,并且您肯定不想自动取消引用它们(想象一下您的代码困惑并意外创建 1GB 大小的副本...哎呀。)你可能会说“好吧,让我们创建一个特征 AutoDeref 让你 #derive 获得自动引用行为。”现在另一个问题开始出现:这会显着增加编译时间和编译器复杂性,因为 Rust 现在需要在任何上下文中取消引用所有原始操作。

TL;DR:这会显着增加编译器的复杂性和编译时间。

关于rust - 为什么对原语的引用没有隐式取消引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74162917/

相关文章:

rust - 如何在Rust中从特定索引开始的子字符串中查找?

rust - 如何在 Rust 中过滤特定子特征的 RCed 特征对象向量?

performance - 优化 rust N 素数生成器

rust - 由于实验功能无法安装沙沙声

rust - 是否有模数(不是余数)函数/操作?

rust - 为什么不能在同一结构中存储值和对该值的引用?

arrays - 如何在 Rust 的结构中实现动态二维数组?

rust - 三明治管使用rust 了怎么办?

macros - 如何在宏中包装一个 do-while 样式循环,保持 'continue' 流控制?

generics - 如何确保泛型类型具有某个字段