Copy และ Clone ต่างกันอย่างไร?


128

ปัญหานี้ดูเหมือนจะบอกเป็นนัยว่าเป็นเพียงรายละเอียดการใช้งานเท่านั้น ( memcpyเทียบกับ ???) แต่ฉันไม่พบคำอธิบายที่ชัดเจนเกี่ยวกับความแตกต่าง


ซอร์สโค้ดของ Rust มีคำอธิบายที่เกี่ยวข้อง
duan

คำตอบ:


115

Cloneได้รับการออกแบบมาสำหรับการทำซ้ำโดยพลการ: การCloneใช้งานสำหรับประเภทTสามารถดำเนินการที่ซับซ้อนโดยพลการที่จำเป็นในการสร้างไฟล์T. มันเป็นลักษณะปกติ (นอกเหนือจากการโหมโรง) ดังนั้นจึงต้องใช้เหมือนลักษณะปกติด้วยการเรียกใช้เมธอดเป็นต้น

Copyลักษณะแทนค่าที่สามารถทำซ้ำได้อย่างปลอดภัยผ่านmemcpy: สิ่งที่ต้องการ reassignments และผ่านการโต้แย้งโดยมูลค่าให้กับฟังก์ชั่นมักจะ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
เย็น! นี่เป็นการเคลียร์คำถามรองที่ฉันมีเกี่ยวกับว่าลักษณะของ Clone มีการคัดลอกโดยปริยายหรือไม่ ปรากฎว่าคำถามนั้นและคำถามนี้เกี่ยวข้องมากกว่าที่ฉันคิด ขอบคุณ!
user12341234

ในตัวอย่างแรกของคุณสมมติว่าคุณต้องการที่yจะได้รับการย้ายไม่สำเนาของมันเช่นเดียวกับตัวอย่างออกความเห็นล่าสุดของคุณx w = vคุณจะระบุได้อย่างไร?
johnbakers

2
คุณทำไม่ได้และไม่ทำเพราะCopyมีขึ้นเพื่อใช้กับประเภท "ราคาถูก" เช่นu8ในตัวอย่าง ถ้าคุณเขียนชนิดหนามากที่คุณคิดว่าการย้ายจะมีประสิทธิภาพมากกว่าสำเนาทำให้มันไม่Copy Impl โปรดทราบว่าในกรณี u8 คุณจะไม่สามารถมีประสิทธิภาพมากขึ้นด้วยการย้ายเนื่องจากอย่างน้อยภายใต้ประทุนอาจมีสำเนาตัวชี้ซึ่งมีราคาแพงพอ ๆ กับสำเนา u8 อยู่แล้วดังนั้นทำไมต้องกังวล
mdup

นี่หมายความว่าการปรากฏตัวของCopyลักษณะมีผลกระทบต่อขอบเขตอายุการใช้งานโดยนัยของตัวแปรหรือไม่? ถ้าเป็นเช่นนั้นฉันคิดว่ามันน่าสนใจ
Brian Cain

7

ตามคำตอบอื่น ๆ ที่กล่าวถึงแล้ว:

  • Copy เป็นนัยราคาไม่แพงและไม่สามารถนำมาใช้ใหม่ได้ (memcpy)
  • Clone มีความชัดเจนอาจมีราคาแพงและอาจนำไปใช้ใหม่โดยพลการ

บางครั้งสิ่งที่ขาดหายไปในการอภิปรายเกี่ยวCopyกับ vs 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();เพื่อหลีกเลี่ยงการย้ายนัยเราอย่างชัดเจนสามารถโทร

สิ่งนี้อาจก่อให้เกิดคำถามว่าจะบังคับย้ายประเภทที่ใช้ลักษณะการคัดลอกได้อย่างไร? . คำตอบสั้น ๆ : คุณทำไม่ได้ / ไม่สมเหตุสมผล


@Shepmaster ฉันลบมันออกแม้ว่าฉันจะพบว่ามันอ่านง่ายกว่ามากเพราะมันมีการเข้ารหัสสีที่ดีของคอมไพเลอร์ Rust และฉันได้ตรวจสอบให้แน่ใจว่ามีคำที่เกี่ยวข้องกับการค้นหาทั้งหมดอยู่ในข้อความด้วย
bluenote10
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.