ไม่สามารถย้ายออกจากเนื้อหาที่ยืมมา / ไม่สามารถย้ายออกจากข้อมูลอ้างอิงที่แชร์ได้


127

cannot move out of borrowed contentฉันไม่เข้าใจข้อผิดพลาด ฉันได้รับมันหลายครั้งและฉันแก้ไขมันมาตลอด แต่ฉันไม่เคยเข้าใจว่าทำไม

ตัวอย่างเช่น:

for line in self.xslg_file.iter() {
    self.buffer.clear();

    for current_char in line.into_bytes().iter() {
        self.buffer.push(*current_char as char);
    }

    println!("{}", line);
}

สร้างข้อผิดพลาด:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:31:33
   |
31 |             for current_char in line.into_bytes().iter() {
   |                                 ^^^^ cannot move out of borrowed content

ใน Rust เวอร์ชันที่ใหม่กว่าข้อผิดพลาดคือ

error[E0507]: cannot move out of `*line` which is behind a shared reference
  --> src/main.rs:31:33
   |
31 |             for current_char in line.into_bytes().iter() {
   |                                 ^^^^ move occurs because `*line` has type `std::string::String`, which does not implement the `Copy` trait

ฉันแก้ไขโดยการโคลนline:

for current_char in line.clone().into_bytes().iter() {

ฉันไม่เข้าใจข้อผิดพลาดแม้ว่าจะอ่านโพสต์อื่น ๆ เช่น:

ที่มาของข้อผิดพลาดแบบนี้คืออะไร?


1
คุณได้ดูคำถามเช่นนี้หรือไม่? (Btw สตริงเสนอ.bytes()วิธีการ)
huon

ใช่ฉันตรวจสอบแล้ว แต่ไม่เข้าใจ :( และสตริงของฉันคือ std :: string :: String ตามเอกสารไม่มีวิธี. ไบต์ ()
Peekmo

4
เรียกว่า.as_bytes()
bluss

อันที่จริงขอบคุณมันใช้งานได้as_bytes()โดยไม่ต้องโคลนนิ่ง แต่ฉันยังไม่เข้าใจว่าทำไม?
Peekmo

Stringได้รับวิธีการจากbytes str
huon

คำตอบ:


108

มาดูลายเซ็นสำหรับinto_bytes:

fn into_bytes(self) -> Vec<u8>

สิ่งนี้ใช้selfไม่ใช่การอ้างอิงถึงตนเอง ( &self) นั่นหมายความว่าselfจะถูกใช้หมดและจะไม่สามารถใช้ได้หลังจากการโทร แทนที่คุณจะได้รับไฟล์Vec<u8>. คำนำหน้าinto_เป็นวิธีทั่วไปในการแสดงถึงวิธีการเช่นนี้

ฉันไม่รู้ว่าiter()วิธีของคุณส่งคืนอย่างไร แต่ฉันเดาว่ามันเป็นตัววนซ้ำ&Stringนั่นคือมันส่งคืนการอ้างอิงไปยัง a Stringแต่ไม่ได้ให้คุณเป็นเจ้าของ นั่นหมายความว่าคุณไม่สามารถเรียกเมธอดที่ใช้ค่าได้

cloneในขณะที่คุณได้พบหนึ่งแก้ปัญหาคือการใช้งาน นี้จะสร้างวัตถุซ้ำว่าคุณจะเป็นเจ้าของและสามารถโทรinto_bytesได้ที่ ตามที่ผู้แสดงความคิดเห็นคนอื่น ๆ กล่าวถึงคุณยังสามารถใช้as_bytesสิ่งที่ต้องใช้&selfจึงจะใช้ได้กับมูลค่าที่ยืมมา คุณควรใช้อันไหนขึ้นอยู่กับเป้าหมายสุดท้ายของสิ่งที่คุณทำกับตัวชี้

ในภาพขนาดใหญ่ทั้งหมดนี้จะทำอย่างไรกับความคิดของการเป็นเจ้าของ การดำเนินการบางอย่างขึ้นอยู่กับการเป็นเจ้าของรายการและการดำเนินการอื่น ๆ สามารถหลีกเลี่ยงได้ด้วยการยืมวัตถุ (อาจจะเปลี่ยนแปลงได้) การอ้างอิง ( &foo) ไม่ได้ให้สิทธิ์ความเป็นเจ้าของเป็นเพียงการยืม

เหตุใดจึงน่าสนใจที่จะใช้selfแทน&selfอาร์กิวเมนต์ของฟังก์ชัน

การโอนความเป็นเจ้าของเป็นแนวคิดที่มีประโยชน์โดยทั่วไปเมื่อฉันทำอะไรบางอย่างอาจมีคนอื่นได้ ใน Rust เป็นวิธีที่มีประสิทธิภาพมากขึ้น ฉันสามารถหลีกเลี่ยงการจัดสรรสำเนาให้คุณหนึ่งสำเนาจากนั้นทิ้งสำเนาของฉัน ความเป็นเจ้าของยังเป็นสถานะที่อนุญาตมากที่สุด ถ้าฉันเป็นเจ้าของวัตถุฉันสามารถทำมันได้ตามที่ฉันต้องการ


นี่คือรหัสที่ฉันสร้างขึ้นเพื่อทดสอบด้วย:

struct IteratorOfStringReference<'a>(&'a String);

impl<'a> Iterator for IteratorOfStringReference<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

struct FileLikeThing {
    string: String,
}

impl FileLikeThing {
    fn iter(&self) -> IteratorOfStringReference {
        IteratorOfStringReference(&self.string)
    }
}

struct Dummy {
    xslg_file: FileLikeThing,
    buffer: String,
}

impl Dummy {
    fn dummy(&mut self) {
        for line in self.xslg_file.iter() {
            self.buffer.clear();

            for current_char in line.into_bytes().iter() {
                self.buffer.push(*current_char as char);
            }

            println!("{}", line);
        }
    }
}

fn main() {}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.