rust .to_owned()、.clone()和dereferencing(*)之间有什么区别吗?

yshpjwxd  于 2023-08-05  发布在  其他
关注(0)|答案(2)|浏览(215)

使用此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的内容。
有什么不同吗?

llew8vvj

llew8vvj1#

对于Copy示例的引用,没有区别。
这是因为对于Copy类型:

  1. *ref_to_val返回val的按位副本(并且不会使旧值无效)。
    1.导出的Clone impl.对于Copy类型,将使用*实现.clone()
    1.毯子ToOwned实施对于Clone类型,将使用.clone()实现.to_owned()

所以这一切都归结为按位复制。

这是你的案子
如果你想了解traits DerefCloneToOwned是如何为!Copy类型工作的,你必须了解它们的用途并阅读特定类型的文档。
我相信Stringstr类型是非常有代表性的!Copy类型,可以帮助你理解其中的魔力。例如,strToOwned,但不是DerefClone。您的示例不适用于这些类型。

xtfmy6hx

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 的情况下通过值返回。这就是ToOwnedClone存在差异的 * 原因 *--支持创建动态大小类型的克隆。

实现Clone的所有类型都通过一揽子实现自动实现ToOwned。因此,以有趣的方式实现ToOwned的唯一类型是那些 * 不 * 实现Clone的类型;这些类型通常是动态调整大小的类型。
要编写好Rust代码:

  • 如果可以使用取值,请执行该操作。
  • 如果无法使用取值,请使用.clone()
  • 如果无法使用.clone(),请使用.to_owned()
  • 如果这些方法都不起作用,请参阅该类型的文档:
  • 它可以具有专门的操作(例如,File::try_clone())的第一个值;
  • 它可能根本上是您无法克隆的,在这种情况下,您可能希望与RcArc共享单个示例,或者您可能需要执行完全不同的操作;或者是
  • 代码的作者可能忘记提供CopyCloneToOwned实现。

相关问题