简体   繁体   English

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

[英]Specify lifetime of a reference to a return argument for a member variable in an associated function

I would like to have a CatMaker struct that can create a Cat , but stores a reference to it internally so that it can later make calls to that Cat (maybe have a CatMaker.get_child_color(&self) function). 我想有一个可以创建CatCatMaker结构,但在内部存储对它的引用,以便稍后可以调用该Cat (可能有一个CatMaker.get_child_color(&self)函数)。 I believe this implies that the CatMaker cannot outlive the Cat (otherwise it would try to deference and the Cat wouldn't be there) and the compiler seems to agree. 我相信这意味着CatMaker不会比Cat CatMaker (否则它会尝试顺从而Cat不会在那里)并且编译器似乎同意。

Here is a code example of what I would like to do: 这是我想要做的代码示例:

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;
}

I'm having trouble figuring out how to specify the lifetime of self.child in CatMaker.make_cat . 我无法弄清楚如何在CatMaker.make_cat指定self.child的生命周期。

You can have CatMaker own the Cat , and make_cat return a reference to the Cat , rather than returning the Cat itself. 您可以让CatMaker拥有Cat ,并且make_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;
}

However, this has a big restriction: you can't use my_cat_maker at all as long as you keep the result of make_cat around – here, it's stored in my_cat , so you can't use my_cat_maker until my_cat goes out of scope. 但是,这有一个很大的限制:你不能使用my_cat_maker你不停的结果都只要make_cat左右-在这里,它存储在my_cat ,所以你不能使用my_cat_maker直到my_cat超出范围。 That's because my_cat keeps a mutable borrow on my_cat_maker , and Rust doesn't allow two mutable borrows to be usable on the same object at the same time. 那是因为my_catmy_cat_maker上保留了一个可变的借my_cat_maker ,并且Rust不允许两个可变的借位同时在同一个对象上使用。

If this restriction is not acceptable to you, you'll need to use another tool to manage the lifetime of the Cat for you. 如果您不接受此限制,则需要使用其他工具来管理Cat的生命周期。 Such a tool is Rc , which is a reference-counted reference to an object. 这样的工具是Rc ,它是对象的引用计数引用。 If you also need to be able to mutate the Cat , you'll need to couple Rc with RefCell , which allows mutating the object in an 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;
}

In make_cat , the .clone() call clones the Rc object, which makes a new reference to the same object, incrementing the reference count. make_cat.clone()调用克隆Rc对象,该对象对同一对象进行新的引用,增加引用计数。 When all related Rc objects are dropped, the reference-counted object is dropped. 删除所有相关的Rc对象后,将删除引用计数的对象。

In main , we need to call borrow_mut() in order to access the Cat . main ,我们需要调用borrow_mut()来访问Cat borrow_mut() returns a RefMut object that protects the Cat from being further borrowed until the RefMut is dropped. borrow_mut()返回一个RefMut对象,该对象保护Cat不被借用,直到RefMut被删除。 If you try to borrow the Cat again while a mutable borrow is active, your program will panic. 如果您在可变借款激活时尝试再次借用Cat ,您的程序将会出现恐慌情绪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM