以下两个例子是等效的吗?
例1:
let x = String::new();
let y = &x[..];
例2:
let x = String::new();
let y = &*x;
一个比另一个更有效还是基本相同?
以下两个例子是等效的吗?
例1:
let x = String::new();
let y = &x[..];
例2:
let x = String::new();
let y = &*x;
一个比另一个更有效还是基本相同?
如果是 String
和 Vec
,他们做同样的事情。在 一般但是,它们并不完全相同。
首先,你必须明白 Deref
。这种特性是在类型在逻辑上“包装”某些较低级别,更简单的值的情况下实现的。例如,所有“智能指针”类型(Box
, Rc
, Arc
) 实行 Deref
让您访问他们的内容。
它也是为了实现的 String
和 Vec
: String
“derefs”更简单 str
, Vec<T>
derefs更简单 [T]
。
写作 *s
只是手动调用 Deref::deref
转 s
进入“更简单的形式”。它几乎总是写的 &*s
然而:虽然 Deref::deref
签名说它返回一个借来的指针(&Target
),编译器插入第二个自动deref。这样就可以了,例如, { let x = Box::new(42i32); *x }
结果是 i32
而不是一个 &i32
。
所以 &*s
真的只是简写 Deref::deref(&s)
。
s[..]
是语法糖 s.index(RangeFull)
,实施 Index
特征。这意味着要切割被索引事物的“整个范围”;对彼此而言 String
和 Vec
,这为您提供了整个内容的一部分。再次,结果是 技术上 一个借来的指针,但Rust自动解除了这个 同样,所以它也几乎总是写的 &s[..]
。
那有什么区别?坚持这个想法;让我们来谈谈 Deref
链接。
举一个具体的例子,因为你可以查看一个 String
作为一个 str
, 这将是 真 有助于提供所有方法 str
自动提供 String
也是。 Rust不是继承而是继承 Deref
链接。
它的工作方式是,当您在值上请求特定方法时,Rust首先查看为该特定类型定义的方法。让我们说它找不到你要求的方法;在放弃之前,Rust会检查一下 Deref
实现。如果找到一个,则调用它然后 再试一次。
这意味着当你打电话时 s.chars()
哪里 s
是一个 String
, 什么是 其实 发生的是你正在打电话 s.deref().chars()
因为 String
不 有 一个叫做的方法 chars
但是 str
不 (向上滚动即可看到 String
只获得此方法,因为它实现 Deref<Target=str>
)。
回到原来的问题,区别 &*s
和 &s[..]
是什么时候发生的事情 s
不是 只是 String
要么 Vec<T>
。我们举几个例子:
s: String
; &*s: &str
, &s[..]: &str
。s: &String
: &*s: &String
, &s[..]: &str
。s: Box<String>
: &*s: &String
, &s[..]: &str
。s: Box<Rc<&String>>
: &*s: &Rc<&String>
, &s[..]: &str
。&*s
只要 曾经 剥掉了 一 间接层。 &s[..]
剥掉了 他们全部。这是因为没有 Box
, Rc
, &
, 等等 实施 Index
特质,所以 Deref
链接导致呼叫 s.index(RangeFull)
链接所有这些中间层。
你应该使用哪一个?无论你想要什么。使用 &*s
(要么 &**s
, 要么 &***s
)如果你想控制 究竟 你要剥离多少个间接层。使用 &s[..]
如果你想将它们全部剥离,只需获得值的最内层表示。
或者,你可以做我做的事情并使用它 &*s
因为它从左到右读,而 &s[..]
从左到右再次读取,这让我很烦。 :)
Deref
强制转换。DerefMut
和 IndexMut
这些都是上述所有,但是 &mut
代替 &
。它们完全相同 String
和 Vec
。
该 [..]
语法导致调用 Index<RangeFull>::index()
而且它不只是糖 [0..collection.len()]
。后者会引入绑定检查的成本。很高兴Rust的情况并非如此,所以他们都同样快。
相关代码:
index
的 String
deref
的 String
index
的 Vec
(只是回来 self
触发deref强制因此执行完全相同的代码 deref
)deref
的 Vec