Masalah ini sepertinya menyiratkan bahwa ini hanya detail implementasi ( memcpy
vs ???), tetapi saya tidak dapat menemukan deskripsi eksplisit tentang perbedaannya.
Masalah ini sepertinya menyiratkan bahwa ini hanya detail implementasi ( memcpy
vs ???), tetapi saya tidak dapat menemukan deskripsi eksplisit tentang perbedaannya.
Jawaban:
Clone
dirancang untuk duplikasi sewenang-wenang: Clone
implementasi untuk suatu jenis T
dapat melakukan operasi rumit sewenang-wenang yang diperlukan untuk membuat yang baru T
. Ini adalah sifat normal (selain di awal), dan karenanya membutuhkan penggunaan seperti sifat normal, dengan pemanggilan metode, dll.
The Copy
sifat mewakili nilai-nilai yang dapat dengan aman digandakan melalui memcpy
: hal-hal seperti penugasan kembali dan melewati sebuah argumen dengan-nilai ke fungsi selalu memcpy
s, dan sebagainya untuk Copy
jenis, compiler mengerti bahwa hal itu tidak perlu mempertimbangkan mereka bergerak .
Clone
salinan dalam, dan Copy
salinan bayangan?
Clone
membuka kemungkinan bahwa tipe dapat melakukan salinan dalam atau dangkal: "rumit secara sewenang-wenang".
Perbedaan utamanya adalah kloning itu eksplisit. Notasi implisit berarti pindah untuk non- Copy
tipe.
// 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.
Omong-omong, setiap Copy
tipe juga harus ada Clone
. Namun, mereka tidak diharuskan melakukan hal yang sama! Untuk tipe Anda sendiri, .clone()
bisa menjadi metode arbitrer pilihan Anda, sedangkan penyalinan implisit akan selalu memicu a memcpy
, bukan clone(&self)
implementasi.
y
dipindahkan x
, bukan salinannya, seperti contoh terakhir yang Anda beri komentar w = v
. Bagaimana Anda menjelaskannya?
Copy
dimaksudkan untuk diterapkan untuk jenis "murah", seperti u8
dalam contoh. Jika Anda menulis tipe yang cukup kelas berat, yang menurut Anda memindahkan lebih efisien daripada salinan, buatlah tidak tersirat Copy
. Perhatikan bahwa dalam kasus u8, Anda tidak mungkin bisa lebih efisien dengan pemindahan, karena di bawah kap itu mungkin setidaknya memerlukan salinan pointer - yang sudah semahal salinan u8, jadi mengapa repot-repot.
Copy
sifat berdampak pada cakupan variabel seumur hidup implisit? Jika demikian saya pikir itu penting.
Seperti yang sudah tercakup oleh jawaban lain:
Copy
implisit, murah, dan tidak dapat diimplementasikan kembali (memcpy).Clone
eksplisit, mungkin mahal, dan dapat diterapkan kembali secara sewenang-wenang.Apa yang terkadang hilang dalam pembahasan Copy
vs Clone
adalah bahwa hal itu juga mempengaruhi bagaimana kompilator menggunakan perpindahan vs salinan otomatis. Misalnya:
#[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);
}
Contoh pertama ( PointCloneAndCopy
) berfungsi dengan baik di sini karena salinan implisit, tetapi contoh kedua ( PointCloneOnly
) akan mengalami kesalahan dengan penggunaan setelah pemindahan:
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
Untuk menghindari pemindahan implisit, kita bisa memanggil secara eksplisit let p2 = p1.clone();
.
Ini mungkin menimbulkan pertanyaan tentang bagaimana memaksa perpindahan dari tipe yang mengimplementasikan sifat Salin? . Jawaban singkatnya: Anda tidak bisa / tidak masuk akal.