为什么String类型的deref()操作返回str的引用,而Asterisk运算符返回str?

Def*_*her 3 rust

我是 Rust 的新学习者,我发现*运算符可以通过Deref特征重载。该std::string::String类型已Deref实现特征,该特征返回&str类型。但是,当我进行以下测试时,编译器告诉我 is 的类型s2,并显示错误消息“编译时无法知道str类型值的大小”。str所以代码无法编译。但问题是为什么s2str?它不应该是同一类型吗s1

let owned = "test".to_string(); // owned type is String
let s1 = owned.deref(); // s1 type is &str
let s2 = *owned; // s2 type is str
Run Code Online (Sandbox Code Playgroud)

Sil*_*olo 5

Deref是 Rust 中的一个特殊特征,规则可以在文档中找到。还有其他一些地方会Deref发生强制转换,但由于您询问了 unary *,因此该页面上的第一条规则与您相关。

如果T实现Deref<Target = U>,并且x是类型 的值T,则:

  • 在不可变上下文中,*x(其中T既不是引用也不是原始指针)相当于*Deref::deref(&x)

所以在Deref::deref调用之后,Rust*再次尝试一元。这可以调用Deref其他类型,如这个问题所示。这也与 C++ 的重载运算符的工作方式相同->。它执行某种(用户定义的)强制,然后尝试再次取消引用,这可能会递归地调用->其他内容。

所以这

let s2 = *owned;
Run Code Online (Sandbox Code Playgroud)

相当于

let s2 = *owned.deref();
Run Code Online (Sandbox Code Playgroud)

并且有类型strstr不是Sized类型,因此不能存储在变量中,这会导致错误。

至于Rust为什么Deref这样做,该特征被定义为获取引用并返回引用。这是有道理的,因为它在幕后强制某种引用,而不是实际创建数据。十分之九,Deref只是返回对外部结构上的一些内部数据的引用(Box这是一个很好的例子)。

另一方面,当您作为程序员编写时*,您显然不需要参考。毕竟,您只是不遗余力地取消引用数据。因此,*允许通过特征进行解引用强制Deref,但在强制完成后仍尝试获取数据的所有权(或复制,如果适用)。