【问题标题】:Is there a difference between slicing and an explicit reborrow when converting Strings to &strs?将字符串转换为 &strs 时,切片和显式重借之间有区别吗?
【发布时间】:2015-11-22 21:58:54
【问题描述】:

以下两个例子是否等价?

示例 1:

let x = String::new();
let y = &x[..];

示例 2:

let x = String::new();
let y = &*x;

一个比另一个更有效还是它们基本相同?

【问题讨论】:

  • 如果适合答案,我还想将问题扩展到Vec<T>&[T]

标签: memory type-conversion rust


【解决方案1】:

对于StringVec,它们做同样的事情。然而,在一般情况下,它们并不完全等价。

首先,你必须了解Deref。这个特性是在一个类型在逻辑上“包装”一些较低级别、更简单的值的情况下实现的。例如,所有“智能指针”类型(BoxRcArc)都实现了Deref,让您可以访问它们的内容。

它也为StringVec 实现:String“derefs”到更简单的strVec<T> derefs 到更简单的[T]

编写*s 只是手动调用Deref::deref 以将s 转换为“更简单的形式”。它几乎总是写成&*s,然而:虽然Deref::deref 签名说它返回一个借用的指针(&Target),但编译器会插入第二个自动取消引用。例如,{ let x = Box::new(42i32); *x } 会产生 i32 而不是 &i32

所以&*s 实际上只是Deref::deref(&s) 的简写。

s[..]s.index(RangeFull) 的语法糖,由Index trait 实现。这意味着对被索引的事物的“整个范围”进行切片;对于StringVec,这将为您提供整个内容的一部分。同样,结果技术上是一个借用的指针,但 Rust 自动取消引用这个以及,所以它也几乎总是写成&s[..]

那么有什么区别呢?保持这个想法;让我们谈谈Deref 链接。

举一个具体的例子,因为您可以将String 视为str,所以让strs 上可用的所有方法自动在@ 上可用真的很有帮助987654364@s 也是如此。 Rust 通过Deref 链接而不是继承。

它的工作方式是,当你请求一个值的特定方法时,Rust 首先查看为该特定类型定义的方法。假设它没有找到您要求的方法;在放弃之前,Rust 会检查 Deref 的实现。如果找到,它会调用它,然后再次尝试

这意味着当您调用 s.chars() 时,其中 sString实际上 发生的是您正在调用 s.deref().chars(),因为 String 不 有一个名为 chars 的方法,但 str does(向上滚动查看 String 只获取此方法,因为它实现了 Deref<Target=str>)。

回到最初的问题,&*s&s[..] 之间的区别在于s 不是只是 StringVec<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[..] 剥离所有这些。这是因为BoxRc&etc. 都没有实现 Index 特征,所以 Deref 链接导致对 s.index(RangeFull) 的调用链接所有这些中间层。

你应该使用哪一个?随便你。如果您想准确地控制要剥离多少层间接,请使用&*s(或&**s,或&***s)。如果您想将它们全部剥离并获取值的最内部表示,请使用 &s[..]

或者,您可以像我一样使用&*s,因为它从左到右读取,而&s[..] 再次从左到右到左读取,这让我很恼火。 :)

附录

【讨论】:

    【解决方案2】:

    StringVec 完全相同。

    [..] 语法导致对Index<RangeFull>::index() 的调用,它不仅仅是[0..collection.len()] 的糖。后者将引入绑定检查的成本。很高兴在 Rust 中不是这种情况,所以它们都同样快。


    相关代码:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      • 2020-03-09
      • 2011-03-30
      • 2018-09-15
      • 1970-01-01
      • 2021-03-02
      • 2015-10-18
      相关资源
      最近更新 更多