亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在不破壞封裝的情況下返回對RefCell內部內容的引用?

如何在不破壞封裝的情況下返回對RefCell內部內容的引用?

Git
慕斯709654 2019-11-19 15:14:33
我有一個具有內部可變性的結構。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 enough17 |     }   |     - 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().vec17 | |     }   | |_____^問題是我無法在該函數上Foo返回借用vec,因為借用vec僅在的有效期內有效Ref,但Ref立即超出范圍。我認為Ref必須堅持,因為:RefCell<T>使用Rust的生命周期來實現“動態借用”,這一過程使人們可以要求對內部價值進行臨時,排他,可變的訪問。RefCell<T>s的借記是在“運行時”進行跟蹤的,這與Rust的本機引用類型不同,后者在編譯時是完全靜態跟蹤的。由于RefCell<T>借貸是動態的,因此可以嘗試借入已經可變借貸的值;當這種情況發生時,將導致任務恐慌?,F在,我可以改寫這樣的函數來返回整個內部:pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;但是,這可能會將字段(MutableInterior.hide_me在此示例中)暴露為真正的私有實現細節Foo。理想情況下,我只想公開vec自身,可能需要配備警衛來實現動態借用行為。然后,呼叫者不必了解hide_me。
查看完整描述

3 回答

?
有只小跳蛙

TA貢獻1824條經驗 獲得超8個贊

您可以創建一個與所Ref<'a,T>返回的后衛類似的新結構RefCell::borrow(),以對其進行包裝Ref并避免其超出范圍,例如:


use std::cell::Ref;


struct FooGuard<'a> {

    guard: Ref<'a, MutableInterior>,

}

然后,您可以Deref為其實現特征,以便可以像使用它一樣使用它&Vec<i32>:


use std::ops::Deref;


impl<'b> Deref for FooGuard<'b> {

    type Target = Vec<i32>;


    fn deref(&self) -> &Vec<i32> {

        &self.guard.vec

    }

}

之后,更新您的get_items()方法以返回FooGuard實例:


impl Foo {

    pub fn get_items(&self) -> FooGuard {

        FooGuard {

            guard: self.interior.borrow(),

        }

    }

}

并Deref做魔術:


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

    let v: &Vec<i32> = &items;

}


查看完整回答
反對 回復 2019-11-19
?
函數式編程

TA貢獻1807條經驗 獲得超9個贊

您可以使用Ref::map(從Rust 1.8開始)而不是創建全新的類型。這與Levans的現有答案具有相同的結果:


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)

    }

}


查看完整回答
反對 回復 2019-11-19
?
侃侃爾雅

TA貢獻1801條經驗 獲得超16個贊

你可以包裝Vec在Rc。


use std::cell::RefCell;

use std::rc::Rc;


struct MutableInterior {

    hide_me: i32,

    vec: Rc<Vec<i32>>,

}

struct Foo {

    interior: RefCell<MutableInterior>,

}


impl Foo {

    pub fn get_items(&self) -> Rc<Vec<i32>> {

        self.interior.borrow().vec.clone() // clones the Rc, not the Vec

    }

}


fn main() {

    let f = Foo {

        interior: RefCell::new(MutableInterior {

            vec: Rc::new(Vec::new()),

            hide_me: 2,

        }),

    };

    let borrowed_f = &f;

    let items = borrowed_f.get_items();

}

當您需要對進行突變時Vec,可使用Rc::make_mut獲取對的可變引用Vec。如果還有其他的Rc小號指的是Vec,make_mut將分離的Rc與其他RcS,克隆Vec和更新本身指的是新的Vec,然后給你一個可變的引用。這樣可以確保其他Rcs中的值不會突然改變(因為Rc它本身不提供內部可變性)。

查看完整回答
反對 回復 2019-11-19
  • 3 回答
  • 0 關注
  • 675 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號