カプセル化を壊さずにRefCell内の何かへの参照を返すにはどうすればよいですか? 質問する

カプセル化を壊さずにRefCell内の何かへの参照を返すにはどうすればよいですか? 質問する

内部可変性を持つ構造体があります。

use std::cell::RefCell;

struct MutableInterior {
    hide_me: i32,
    vec: Vec<i32>,
}
struct Foo {
    //although not used in this particular snippet,
    //the motivating problem uses interior mutability
    //via RefCell.
    interior: RefCell<MutableInterior>,
}

impl Foo {
    pub fn get_items(&self) -> &Vec<i32> {
        &self.interior.borrow().vec
    }
}

fn main() {
    let f = Foo {
        interior: RefCell::new(MutableInterior {
            vec: Vec::new(),
            hide_me: 2,
        }),
    };
    let borrowed_f = &f;
    let items = borrowed_f.get_items();
}

次のエラーが発生します:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:16:10
   |
16 |         &self.interior.borrow().vec
   |          ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 |     }
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 | /     pub fn get_items(&self) -> &Vec<i32> {
16 | |         &self.interior.borrow().vec
17 | |     }
   | |_____^

Foo問題は、借用した を返す関数を に持てないことですvec。借用した はvecの存続期間中のみ有効ですRefが、 はRefすぐにスコープ外になるからです。

Ref私はそれが残るべきだと思っているなぜなら:

RefCell<T>Rust のライフタイムを使用して「動的借用」を実装します。これは、内部値への一時的、排他的、可変アクセスを要求できるプロセスです。RefCell<T>s の借用は、コンパイル時に完全に静的に追跡される Rust のネイティブ参照型とは異なり、「実行時」に追跡されます。RefCell<T>借用は動的であるため、すでに可変借用されている値を借用しようとする可能性があります。これが発生すると、タスク パニックが発生します。

代わりに、内部全体を返す次のような関数を記述することもできます。

pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;

MutableInterior.hide_meただし、これにより、実際にはプライベートな実装の詳細であるフィールド (この例では ) が公開される可能性がありますFoo

vec理想的には、自体を公開し、動的な借用動作を実装するためのガードも用意したいだけです。そうすれば、呼び出し側は について知る必要がなくなりますhide_me

ベストアンサー1

まったく新しいタイプを作成する代わりに、Ref::map(Rust 1.8以降) これは次のコードと同じ結果になります。レヴァンスの既存の回答:

use std::cell::Ref;

impl Foo {
    pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}

API からをimpl Trait非表示にするなどの新しい機能を使用することもできます。Ref

use std::cell::Ref;
use std::ops::Deref;

impl Foo {
    pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ {
        Ref::map(self.interior.borrow(), |mi| &mi.vec)
    }
}

おすすめ記事