在Rust中,解引用和调用clone()以及调用` to_owned之间有什么区别吗?

a8jjtwal  于 2023-04-30  发布在  其他
关注(0)|答案(1)|浏览(263)

下面两行Rust代码有什么区别吗?

let my_reference_type : &SomeType;

let a = my_reference_type.to_owned();
let b = (*my_reference_type).clone();

我意识到对引用类型调用clone()会直接创建引用的克隆。换句话说,返回的类型也是一个引用,并且可能是(?)是否引用了先前存在的引用所引用的同一对象?

k5ifujac

k5ifujac1#

我意识到对引用类型调用clone()会直接创建引用的克隆。换句话说,返回的类型也是一个引用
这不是(普遍)真实的。
你可以自己看。例如,在playground上。

fn main() {
  let a_string: String = "foo".to_string();
  
  let a_string_ref = &a_string;
  
  let a_string_owned: String = a_string_ref.to_owned();
  
  // Note my explicit type annotation. It's String, not &String
  let a_string_cloned_from_ref: String = a_string_ref.clone();
  
}

如果将最后一行的类型从String更改为&String,则会出现编译器错误。
就我所知,这就是为什么它是这样工作的原因。
有一些微妙之处围绕着哪些traits是为哪些类型实现的,但也围绕着哪些方法是为哪些类型实现的。
让我们从Clone trait开始。如果你为T类型实现Clone,就会有一个clone(&self) -> T方法。请注意,clone的参数的类型为&self。这意味着为类型T实现Clone意味着为类型&T实现方法clone
现在让我们考虑一下你提出的两个案例:

调用clone获取&String

这只是标准方法的分辨率:你有一个类型&String和一个方法clone(&String),因为,这可能是微妙的部分,String实现了Clone
因为与类型完全匹配的方法在方法解析中占据“第一位”,所以这就是您得到的:请参阅here以获得深入的解释。

String上调用clone

你可能认为这是“标准路径”,但事实并非如此。String实现了Clone,这意味着存在一个方法clone(&self),但正如您所看到的,参数的类型是&String,而不是String
那么接下来呢?这就是[深入解释](https://doc.rust-lang.org/reference/expressions/method-call-expr.html)又进来了。如果没有方法,无论是在类型本身还是在它的traits上,完全匹配的类型,编译器也会考虑一堆其他类型:

  • 它将尽可能频繁地对给定类型进行deref,并将结果类型作为候选类型抛出到列表中
  • 对于列表中的每个候选项,它将向列表中添加对该类型的引用和对该类型的mut引用
  • 然后它会尝试,直到找到匹配的方法。

因此,在我们的例子中,在寻找一个接受Stringclone方法之后,它现在将寻找一个接受&Stringclone方法。这当然是存在的,所以现在我们又回到了“在引用上调用clone”

克隆引用本身呢

在这种情况下,按照上面的解释,您需要在引用的引用上调用clone,以便顺序按照您需要的方式进行:

let cloned_reference: &String = (&a_string_ref).clone();

但是引用都是Copy,所以你也可以这样做:

let copied_reference: &String = a_string_ref;

相关问题