Không thể di chuyển ra khỏi nội dung mượn / không thể di chuyển ra phía sau một tài liệu tham khảo được chia sẻ


127

Tôi không hiểu lỗi cannot move out of borrowed content. Tôi đã nhận được nó nhiều lần và tôi đã luôn giải quyết nó, nhưng tôi chưa bao giờ hiểu tại sao.

Ví dụ:

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);
}

tạo ra lỗi:

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

Trong các phiên bản mới hơn của Rust, lỗi là

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

Tôi đã giải quyết nó bằng cách nhân bản line:

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

Tôi không hiểu lỗi ngay cả sau khi đọc các bài viết khác như:

Nguồn gốc của loại lỗi này là gì?


1
Bạn đã xem những câu hỏi như thế này chưa? (Btw, chuỗi cung cấp .bytes()phương thức.)
huon

Vâng, tôi đã xem xét nó, nhưng không hiểu :( Và chuỗi của tôi là std :: string :: String, theo tài liệu, không có phương thức .bytes ()
Peekmo

4
Nó được gọi là.as_bytes()
bluss

Trong thực tế, cảm ơn bạn, nó hoạt động as_bytes()mà không cần nhân bản. Nhưng tôi vẫn không hiểu tại sao?
Peekmo

Stringđược bytesphương pháp từ str.
huon

Câu trả lời:


108

Hãy nhìn vào chữ ký cho into_bytes:

fn into_bytes(self) -> Vec<u8>

Điều này mất self, không phải là một tài liệu tham khảo cho bản thân ( &self). Điều đó có nghĩa là selfsẽ được tiêu thụ và sẽ không có sẵn sau cuộc gọi. Ở vị trí của nó, bạn nhận được một Vec<u8>. Tiền tố into_là một cách phổ biến để biểu thị các phương thức như thế này.

Tôi không biết chính xác iter()phương thức của bạn trả về cái gì , nhưng tôi đoán là nó lặp đi lặp lại &String, nghĩa là nó trả về các tham chiếu đến một Stringnhưng không cho bạn quyền sở hữu chúng. Điều đó có nghĩa là bạn không thể gọi một phương thức tiêu thụ giá trị .

Như bạn đã tìm thấy, một giải pháp là sử dụng clone. Điều này tạo ra một đối tượng trùng lặp mà bạn làm của riêng, và có thể gọi into_bytesvề. Như các nhà bình luận khác đề cập, bạn cũng có thể sử dụng as_bytescái nào &self, vì vậy nó sẽ hoạt động dựa trên giá trị vay. Cái nào bạn nên sử dụng phụ thuộc vào mục tiêu cuối cùng của bạn cho những gì bạn làm với con trỏ.

Trong bức tranh lớn hơn, tất cả phải làm với khái niệm quyền sở hữu . Một số hoạt động nhất định phụ thuộc vào việc sở hữu vật phẩm và các hoạt động khác có thể thoát khỏi việc mượn đối tượng (có thể là đột biến). Một tài liệu tham khảo ( &foo) không cấp quyền sở hữu, nó chỉ là một khoản vay.

Tại sao nó thú vị để sử dụng selfthay vì &selftrong các đối số của hàm?

Chuyển quyền sở hữu là một khái niệm hữu ích nói chung - khi tôi hoàn thành một việc gì đó, người khác có thể có nó. Trong Rust, đó là một cách hiệu quả hơn. Tôi có thể tránh phân bổ một bản sao, đưa cho bạn một bản, sau đó vứt bỏ bản sao của mình. Quyền sở hữu cũng là trạng thái cho phép nhất; nếu tôi sở hữu một đối tượng tôi có thể làm với nó như tôi muốn.


Đây là mã mà tôi đã tạo để kiểm tra:

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() {}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.