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();
}
1条答案
按热度按时间k5ifujac1#
我意识到对引用类型调用clone()会直接创建引用的克隆。换句话说,返回的类型也是一个引用
这不是(普遍)真实的。
你可以自己看。例如,在playground上。
如果将最后一行的类型从
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上,完全匹配的类型,编译器也会考虑一堆其他类型:
因此,在我们的例子中,在寻找一个接受
String
的clone
方法之后,它现在将寻找一个接受&String
的clone
方法。这当然是存在的,所以现在我们又回到了“在引用上调用clone”克隆引用本身呢
在这种情况下,按照上面的解释,您需要在引用的引用上调用
clone
,以便顺序按照您需要的方式进行:但是引用都是
Copy
,所以你也可以这样做: