使用此code on the rust playground:
fn main() {
let a = &[1, 2, 3];
let mut o = a.to_owned();
let mut c = a.clone();
let mut d = *a;
o[0] = 7;
c[0] = 8;
d[0] = 9;
println!("o: {:?}", o);
println!("c: {:?}", c);
println!("d: {:?}", d);
println!("a: {:?}", a);
}
字符串
我明白了:
o: [7, 2, 3]
c: [8, 2, 3]
d: [9, 2, 3]
a: [1, 2, 3]
型
这三种方法都克隆了a
的内容。
有什么不同吗?
2条答案
按热度按时间llew8vvj1#
对于
Copy
示例的引用,没有区别。这是因为对于
Copy
类型:*ref_to_val
返回val
的按位副本(并且不会使旧值无效)。1.导出的
Clone
impl.对于Copy
类型,将使用*
实现.clone()
。1.毯子
ToOwned
实施对于Clone
类型,将使用.clone()
实现.to_owned()
。所以这一切都归结为按位复制。
这是你的案子
如果你想了解traits
Deref
,Clone
,ToOwned
是如何为!Copy
类型工作的,你必须了解它们的用途并阅读特定类型的文档。我相信
String
和str
类型是非常有代表性的!Copy
类型,可以帮助你理解其中的魔力。例如,str
是ToOwned
,但不是Deref
或Clone
。您的示例不适用于这些类型。xtfmy6hx2#
假设所有相关的特性都被合理地实现了,那么这三个特性将具有相同的 * 结果 *,并且在使用优化进行编译时应该同样有效。不同之处在于在什么条件下允许哪些,以及它们保证了什么。因此,如果您编写的是 * 泛型 * 代码(可用于许多不同类型的代码),那么您选择哪一个可能很重要,但是如果代码不是泛型的,那么除了可读性之外,这并不重要。
*
解引用(不立即引用结果)将仅在您正在解引用的引用的引用对象(&T
中的T
)实现Copy
特征时进行编译。在这种情况下,可以保证结果是引用所指向的原始值的完全逐字节的副本。.clone()
,也就是Clone::clone()
,只有在引用对象的类型实现了Clone
特征的情况下才会编译。在这种情况下,可以保证结果与引用对象的类型相同:它从&T
变为T
。没有编译器强制保证值是相同的,但是Clone
的实现会有意义地给予“相同值的另一个副本,”即使它的字节表示不同;例如,克隆一个Vec
将给予一个Vec
,它有一个不同的堆分配指针,但内容将是原始向量内容的克隆。所有实作
Copy
的型别也必须实作Clone
,而且您可以合理地预期,这些型别使用其中任何一个都会产生相同的结果。(也就是说,如果Clone::clone()
执行了与复制不同的操作,则该实现违反了所记录的预期。).to_owned()
(即ToOwned::to_owned()
)仅在引用对象的类型实现ToOwned
特征时才进行编译。这个特性本质上与Clone
相同,只是结果类型不需要与引用对象类型相同;例如,在&str
上调用.to_owned()
将给予String
,而不是str
-这很好,因为str
* 不能 * 在没有一些 Package 的情况下通过值返回。这就是ToOwned
与Clone
存在差异的 * 原因 *--支持创建动态大小类型的克隆。实现
Clone
的所有类型都通过一揽子实现自动实现ToOwned
。因此,以有趣的方式实现ToOwned
的唯一类型是那些 * 不 * 实现Clone
的类型;这些类型通常是动态调整大小的类型。要编写好Rust代码:
.clone()
。.clone()
,请使用.to_owned()
。File::try_clone()
)的第一个值;Rc
或Arc
共享单个示例,或者您可能需要执行完全不同的操作;或者是Copy
、Clone
或ToOwned
实现。