将字符串转换为&strs时,切片和显式重新插入之间是否存在差异?

cha*_*had 11 memory type-conversion rust

以下两个例子是等效的吗?

例1:

let x = String::new();
let y = &x[..];
Run Code Online (Sandbox Code Playgroud)

例2:

let x = String::new();
let y = &*x;
Run Code Online (Sandbox Code Playgroud)

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

DK.*_*DK. 10

在的情况下,StringVec他们做同样的事情.但总的来说,它们并不完全相同.

首先,你必须明白Deref.这种特性是在类型在逻辑上"包装"某些较低级别,更简单的值的情况下实现的.例如,所有的"智能指针"类型的(Box,Rc,Arc)执行Deref给你访问他们的内容.

它也实现了StringVec:String"derefs"更简单str,Vec<T>derefs更简单[T].

编写*s只是手动调用Deref::deref以变​​成s"更简单的形式".&*s然而,它几乎总是被写入:虽然Deref::deref签名表示它返回一个借来的指针(&Target),但编译器会插入第二个自动deref.例如,这{ let x = Box::new(42i32); *x }导致i32而不是a &i32.

所以&*s真的只是简写Deref::deref(&s).

s[..]是特征糖s.index(RangeFull),由Index特质实现.这意味着要对被索引事物的"整个范围"进行分割; 两个StringVec,这给你的全部内容的片段.再次,结果是技术上借来的指针,但防锈自动derefs这一个,以及,所以它也几乎总是写&s[..].

那有什么区别?坚持这个想法; 我们来谈谈Deref链接.

举一个具体的例子,因为你可以将a String视为a str,所以在s上自动提供所有可用的方法也是非常有帮助的.Rust不是继承,而是通过链接实现这一点.strStringDeref

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

这意味着,当你调用s.chars()其中s的一个String,什么是真正发生的事情是,你打电话s.deref().chars(),因为String具有一个调用的方法chars,但str (滚动地看到,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[..]所有这些都剥掉了.这是因为没有Box,Rc,&,等等实现Index的性状,所以Deref链接原因调用s.index(RangeFull)通过所有这些中间层以链.

你应该使用哪一个?无论你想要什么.如果要准确控制要剥离的间接层数,请使用&*s(或&**s,或&***s).使用如果要剥夺他们全部关闭,并刚刚获得的价值的最里面的表示.&s[..]

或者,你可以做我做的和使用,&*s因为它从左到右&s[..]阅读,而从左到右再次读取,这让我很烦.:)

附录


Luk*_*odt 6

他们是完全为同StringVec.

[..]语法结果在一个呼叫Index<RangeFull>::index(),它不只是糖[0..collection.len()].后者会引入绑定检查的成本.很高兴Rust的情况并非如此,所以他们都同样快.


相关代码: