以下两个例子是等效的吗?
例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 的 Stringderef 的 Stringindex 的 Vec (只是回来 self 触发deref强制因此执行完全相同的代码 deref)deref 的 Vec