Masalah ini sepertinya menyiratkan bahwa ini hanya detail implementasi ( memcpyvs ???), tetapi saya tidak dapat menemukan deskripsi eksplisit tentang perbedaannya.
Masalah ini sepertinya menyiratkan bahwa ini hanya detail implementasi ( memcpyvs ???), tetapi saya tidak dapat menemukan deskripsi eksplisit tentang perbedaannya.
Jawaban:
Clonedirancang untuk duplikasi sewenang-wenang: Cloneimplementasi untuk suatu jenis Tdapat 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 Copysifat mewakili nilai-nilai yang dapat dengan aman digandakan melalui memcpy: hal-hal seperti penugasan kembali dan melewati sebuah argumen dengan-nilai ke fungsi selalu memcpys, dan sebagainya untuk Copyjenis, compiler mengerti bahwa hal itu tidak perlu mempertimbangkan mereka bergerak .
Clonesalinan dalam, dan Copysalinan bayangan?
Clonemembuka 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- Copytipe.
// 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 Copytipe 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.
ydipindahkan x, bukan salinannya, seperti contoh terakhir yang Anda beri komentar w = v. Bagaimana Anda menjelaskannya?
Copydimaksudkan untuk diterapkan untuk jenis "murah", seperti u8dalam 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.
Copysifat 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 Copyvs Cloneadalah 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.