Kode kerja pertama:

use std::cell::{Ref, RefCell};
use std::rc::Rc;

struct ValueHolder {
    value: i32
}

fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> Ref<i32> {
    Ref::map(
        (**wrapped).borrow(),
        |borrowed| { &(*borrowed).value },
    )
}

fn main() {
    println!("Our value: {}", *give_value(
        &Rc::new(RefCell::new(ValueHolder { value: 1337 }))
    ));
}

Bagian yang relevan adalah fungsi give_value.

Saya ingin mengembalikan Ref ke sesuatu di dalam Rc<RefCell<>>, dalam hal ini nilai di dalam struct.

Itu bekerja dengan baik, tetapi karena saya baru mulai belajar Rust, saya bertanya-tanya, bagaimana saya bisa mencapai hal yang sama tanpa menggunakan Ref::map.

Pendekatan "naif":

fn give_value(wrapped: &Rc<RefCell<ValueHolder>>) -> &i32 {
    &(*(**wrapped).borrow()).value
}

Gagal karena alasan yang jelas:

error[E0515]: cannot return value referencing temporary value
 --> src/bin/rust_example.rs:9:5
  |
9 |     &(*(**wrapped).borrow()).value
  |     ^^^--------------------^^^^^^^
  |     |  |
  |     |  temporary value created here
  |     returns a value referencing data owned by the current function

Jadi pertanyaan saya adalah: Bagaimana saya bisa membuat ulang apa yang fungsi Ref::map lakukan sendiri?

2
Harald Meisner 20 November 2020, 02:23

1 menjawab

Jawaban Terbaik

Anda tidak bisa. RefCell mengharuskan Ref digunakan kapan pun nilainya digunakan, jadi ia tahu kapan harus mengizinkan peminjaman. Ketika Ref dijatuhkan, ini memberi sinyal ke RefCell bahwa itu dapat mengurangi jumlah pinjaman, dan jika jumlah pinjaman adalah 0, maka pinjaman yang dapat berubah dapat terjadi. Mampu memperoleh referensi ke data internal yang tidak meminjam Ref (perhatikan bahwa referensi yang dapat Anda kembalikan dari suatu fungsi tidak dapat meminjam Ref jika tidak, Anda akan merujuk sementara) akan bermasalah, karena Ref dapat dijatuhkan dan RefCell berpikir bahwa ia dapat meminjamkan pinjaman yang dapat berubah, tetapi masih ada pinjaman yang tidak dapat diubah untuk data. Kode sumber untuk Ref::map adalah:

pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
where
    F: FnOnce(&T) -> &U,
{
    Ref { value: f(orig.value), borrow: orig.borrow }
}

Yang menggunakan bidang pribadi yang tidak dapat Anda akses. Jadi, tidak, Anda tidak dapat membuat ulang Ref::map sendiri.

4
Aplet123 19 November 2020, 23:41