指定关联函数中成员变量的返回参数的引用的生存期

时间:2016-01-03 16:41:18

标签: rust

我希望有一个CatMaker结构可以创建Cat,但在内部存储对它的引用,以便以后可以调用Cat(也许有CatMaker.get_child_color(&self)功能)。我相信这意味着CatMaker不能比Cat更长(否则它会尝试顺从而Cat不会存在)并且编译器似乎同意。

以下是我想要做的代码示例:

pub enum CoatColor {
    Black,
    Tabby,
}

pub struct Cat {
    color: CoatColor,
}

pub struct CatMaker<'a> {
    child: Option<&'a Cat>,
}

impl<'a> CatMaker<'a> {
    pub fn new() -> CatMaker<'a> {
        CatMaker{ child: None }
    }

    pub fn make_cat(&mut self, color: CoatColor) -> Cat {
        let new_cat = Cat{ color: color };
        self.child = Some(&new_cat); // commenting out this line will allow it to compile
        new_cat
    }
}

fn main() {
    let mut my_cat_maker = CatMaker::new();
    let mut my_cat = my_cat_maker.make_cat(CoatColor::Black);
    my_cat.color = CoatColor::Tabby;
}

我无法确定如何在self.child中指定CatMaker.make_cat的生命周期。

1 个答案:

答案 0 :(得分:2)

您可以CatMaker拥有Catmake_cat会返回对Cat的引用,而不是返回Cat本身。

pub enum CoatColor {
    Black,
    Tabby,
}

pub struct Cat {
    color: CoatColor,
}

pub struct CatMaker {
    child: Option<Cat>,
}

impl CatMaker {
    pub fn new() -> CatMaker {
        CatMaker { child: None }
    }

    pub fn make_cat(&mut self, color: CoatColor) -> &mut Cat {
        let new_cat = Cat { color: color };
        self.child = Some(new_cat);
        self.child.as_mut().unwrap()
    }
}

fn main() {
    let mut my_cat_maker = CatMaker::new();
    let mut my_cat = my_cat_maker.make_cat(CoatColor::Black);
    my_cat.color = CoatColor::Tabby;
}

但是,这有一个很大的限制:只要保持my_cat_maker的结果,就不能使用make_cat - 这里,它存储在my_cat中,所以在my_cat_maker超出范围之前,您无法使用my_cat。那是因为my_catmy_cat_maker上保留了一个可变的借位,并且Rust不允许两个可变借位同时在同一个对象上使用。

如果您不接受此限制,则需要使用其他工具来管理Cat的生命周期。这样的工具是Rc,它是对象的引用计数引用。如果您还需要能够改变Cat,则需要将RcRefCell结合,这样可以在Rc中改变对象。

use std::cell::RefCell;
use std::rc::Rc;

pub enum CoatColor {
    Black,
    Tabby,
}

pub struct Cat {
    color: CoatColor,
}

pub struct CatMaker {
    child: Option<Rc<RefCell<Cat>>>,
}

impl CatMaker {
    pub fn new() -> CatMaker {
        CatMaker { child: None }
    }

    pub fn make_cat(&mut self, color: CoatColor) -> Rc<RefCell<Cat>> {
        let new_cat = Rc::new(RefCell::new(Cat { color: color }));
        self.child = Some(new_cat.clone());
        new_cat
    }
}

fn main() {
    let mut my_cat_maker = CatMaker::new();
    let my_cat = my_cat_maker.make_cat(CoatColor::Black);
    my_cat.borrow_mut().color = CoatColor::Tabby;
}

make_cat中,.clone()调用克隆Rc对象,该对象对同一对象进行新引用,增加引用计数。删除所有相关的Rc对象后,将删除引用计数对象。

main中,我们需要致电borrow_mut()才能访问Catborrow_mut()返回一个RefMut对象,可以保护Cat不被借用,直到RefMut被删除。如果您在可变借入激活时尝试再次借用Cat,您的程序将会出现恐慌。