Яка різниця між копією та клоном?


Відповіді:


115

Cloneпризначений для довільних дублювань: Cloneреалізація для типу Tможе робити довільно складні операції, необхідні для створення нового T. Це нормальна ознака (крім того, що є прелюдією), і тому вимагає використання, як звичайна ознака, з викликами методів тощо.

Ця Copyознака представляє значення, які можна безпечно дублювати через memcpy: такі речі, як перепризначення та передача функції-значення аргументу функції, завжди є memcpys, і тому для Copyтипів компілятор розуміє, що їм не потрібно вважати цей крок .


5
Чи можу я зрозуміти, що Cloneце копія, і Copyяк тіньова копія?
Djvu

11
Cloneвідкриває можливість того, що тип може зробити або глибоку, або дрібну копію: "довільно складно".
poolie

85

Основна відмінність полягає в тому, що клонування є явним. Неявне позначення означає переміщення для нетипового Copyтипу.

// u8 implements Copy
let x: u8 = 123;
let y = x;
// x can still be used
println!("x={}, y={}", x, y);

// Vec<u8> implements Clone, but not Copy
let v: Vec<u8> = vec![1, 2, 3];
let w = v.clone();
//let w = v // This would *move* the value, rendering v unusable.

До речі, Copyвимагається також кожен тип Clone. Однак вони не зобов’язані робити те саме! Для ваших власних типів .clone()може бути довільним методом на ваш вибір, тоді як неявна копіювання завжди викликає a memcpy, а не clone(&self)реалізацію.


1
Класно! Це очищує вторинне питання, яке у мене виникло щодо того, чи забезпечує ознака клонування неявне копіювання. Виявляється, це питання і це було більше пов'язане, ніж я думав. Дякую!
користувач12341234

У першому прикладі, припустимо , що ви хотіли , yщоб отримати переміщений x, а не його копію, як з вашого останнього закоментувавши прикладу w = v. Як би ви це вказали?
johnbakers

2
Ти не можеш, і ні, бо Copyпризначений для впровадження для "дешевих" типів, як, наприклад, u8у прикладі. Якщо ви пишете досить важкий тип, для якого ви вважаєте, що хід більш ефективний, ніж копія, зробіть це не імпортом Copy. Зверніть увагу, що у випадку u8 ви не можете бути більш ефективними з переміщенням, оскільки під кришкою це, мабуть, спричинить принаймні копію вказівника - яка вже така ж дорога, як копія u8, то чому б це турбувати.
mdup

Чи означає це, що наявність Copyознаки впливає на неявні сфери використання змінних? Якщо так, я вважаю, що це примітно.
Брайан Каїн

7

Як уже висвітлено в інших відповідях:

  • Copy неявна, недорога і не може бути повторно реалізована (memcpy).
  • Clone є явним, може бути дорогим і може бути повторно реалізовано довільно.

Чого іноді не вистачає в обговоренні Copyvs, Cloneце те, що це також впливає на те, як компілятор використовує переміщення проти автоматичних копій. Наприклад:

#[derive(Debug, Clone, Copy)]
pub struct PointCloneAndCopy {
    pub x: f64,
}

#[derive(Debug, Clone)]
pub struct PointCloneOnly {
    pub x: f64,
}

fn test_copy_and_clone() {
    let p1 = PointCloneAndCopy { x: 0. };
    let p2 = p1; // because type has `Copy`, it gets copied automatically.
    println!("{:?} {:?}", p1, p2);
}

fn test_clone_only() {
    let p1 = PointCloneOnly { x: 0. };
    let p2 = p1; // because type has no `Copy`, this is a move instead.
    println!("{:?} {:?}", p1, p2);
}

Перший приклад ( PointCloneAndCopy) працює тут чудово через неявну копію, але другий приклад ( PointCloneOnly) помилиться при використанні після переміщення:

error[E0382]: borrow of moved value: `p1`
  --> src/lib.rs:20:27
   |
18 |     let p1 = PointCloneOnly { x: 0. };
   |         -- move occurs because `p1` has type `PointCloneOnly`, which does not implement the `Copy` trait
19 |     let p2 = p1;
   |              -- value moved here
20 |     println!("{:?} {:?}", p1, p2);
   |                           ^^ value borrowed here after move

Щоб уникнути неявного ходу, ми могли б чітко зателефонувати let p2 = p1.clone();.

Це може поставити питання про те, як змусити перемістити тип, який реалізує ознаку Copy? . Коротка відповідь: Ви не можете / не має сенсу.


@Shepmaster Я видалив його, хоча вважаю його набагато більш читабельним, оскільки він містить приємне кольорове кодування компілятора Rust, і я спеціально переконався, що всі слова, що стосуються пошуку, також містяться в тексті.
bluenote10
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.