内部可変性を持つ構造体があります。
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)
}
}