2017-11-01 40 views
5

Tôi có cấu trúc chứa cả dữ liệu và nhà văn mà cuối cùng sẽ được sử dụng để ghi dữ liệu. Cấu trúc được gói trong một RefCell. Đây là một bản tái tạo nhỏ:Lỗi khi cố gắng mượn 2 trường từ cấu trúc được bao bọc trong RefCell

use std::cell::RefCell; 
use std::io::Write; 

struct Data { 
    string: String, 
} 

struct S { 
    data: Data, 
    writer: Vec<u8>, 
} 

fn write(s: RefCell<S>) { 
    let mut mut_s = s.borrow_mut(); 
    let str = &mut_s.data.string; 
    mut_s.writer.write(str.as_bytes()); 
} 

Trình biên dịch là tức giận:

error[E0502]: cannot borrow `mut_s` as mutable because it is also borrowed as immutable 
    --> src\main.rs:16:5 
    | 
15 |  let str = &mut_s.data.string; 
    |    ----- immutable borrow occurs here 
16 |  mut_s.writer.write(str.as_bytes()); 
    |  ^^^^^ mutable borrow occurs here 
17 | } 
    | - immutable borrow ends here 

Có một API khác nhau tôi nên sử dụng?

Trả lời

9

Bạn có thể tự gọi DerefMut và sau đó lưu tài liệu tham khảo kết quả:

fn write(s: RefCell<S>) { 
    let mut mut_s = s.borrow_mut(); 
    let mut tmp = &mut *mut_s; 
    let str = &tmp.data.string; 
    tmp.writer.write(str.as_bytes()); 
} 

Vấn đề là borrow_mut không trả lại struct của bạn trực tiếp - nó trả về một RefMut. Thông thường, điều này là minh bạch khi cấu trúc này triển khai DerefDerefMut, vì vậy bất kỳ phương thức nào được gọi trên nó đều được chuyển đến kiểu cơ bản. Mã pseduo-mở rộng trông giống như sau:

use std::cell::RefMut; 
use std::ops::{Deref, DerefMut}; 

fn write(s: RefCell<S>) { 
    let mut mut_s: RefMut<S> = s.borrow_mut(); 
    let str = &Deref::deref(&mut_s).data.string; 
    DerefMut::deref_mut(&mut mut_s).writer.write(str.as_bytes()); 
} 

Rust không theo dõi lĩnh vực cấp vay mượn khắp gọi hàm (ngay cả đối với Deref::deref hoặc DerefMut::deref_mut). Điều này gây ra lỗi của bạn, vì phương thức deref_mut sẽ cần phải được gọi trong suốt khoản vay chưa thanh toán từ Deref::deref trước đó.

Phiên bản mở rộng với các mượn rõ ràng trông như thế này, với một cuộc gọi duy nhất để Deref::deref_mut: sau đó

use std::cell::RefMut; 
use std::ops::DerefMut; 

fn write(s: RefCell<S>) { 
    let mut mut_s: RefMut<S> = s.borrow_mut(); 
    let tmp: &mut S = DerefMut::deref_mut(&mut mut_s); 
    let str = &tmp.data.string; 
    tmp.writer.write(str.as_bytes()); 
} 

Trình biên dịch có thể theo dõi rằng hai vay mượn từ đó giá trị tạm thời là rời nhau.


Lưu ý rằng vấn đề này không phải là độc đáo-RefCell! Bất kỳ loại nào triển khai DerefMut đều có thể gặp sự cố tương tự. Dưới đây là một số từ các thư viện chuẩn:

Các vấn đề liên quan