借用新对象实例时如何指定生命周期?

How to specify a lifetime when borrowing a new object instance?

我想用 fill 函数范围内的 Foo 实例填充 Vec<Foo>。这甚至可能生锈吗?我尝试过生命周期,但我无法将我从 tutorials/documentation/samples 中学到的东西投射到这个特定的用例上。

pub struct Foo {
    pub integer: Box<u32>,
}

pub fn fill1(mut vec: Vec<&Foo>) {
    // Error: argument requires that borrow lasts for `'1`
    vec.push(&Foo { integer: Box::new(1) });
}

pub fn fill2<'a>(mut vec: Vec<&'a Foo>) {
    // Error: argument requires that borrow lasts for `'a`
    vec.push(&Foo { integer: Box::new(1) });
}

如果这没有意义(我很乐意理解为什么),我正在考虑修改 pub fn fill3(mut vec: Vec<Foo>, foos: Foos) 的方法签名(不借用)。但是,如果我这样做,我还有很多其他问题。

Playground

这行不通,因为您正在推送对局部变量的引用,这些引用将在方法完成时被销毁。如果您像这样重写方法,可以更容易地看到这一点:

pub fn fill1(mut vec: Vec<&Foo>) {
    // a local variable - exists only within the stack frame of the method
    let foo = Foo { integer: Box::new(1) };

    // `&foo` will be a dangling reference after the method exits
    vec.push(&foo);

} // foo is destroyed here, but `vec` still exists, containing pointers to freed memory, or memory used by some other function

But in this case, why would this work? fn fill(mut vec: Vec<Foo>, foos: Foos)

它将某种工作,但在该方法结束时,您的整个向量将被删除(解除分配),所以这个版本的fill()不正确任何一个。相反,您应该接受对可变向量的引用,这意味着其他人拥有该向量,但它为您提供了修改它的临时访问权限:

// vec is a mutable reference, thus the vector's
// life is not tied with the function execution
// i.e. it will still exist after the function executes
pub fn fill_ok(vec: &mut Vec<Foo>) { 
    let foo = Foo {
        integer: Box::new(1),
    };

    // `foo` is copied to the vector, which is 
    // backed by a heap allocation. The local 
    // variable `foo` will still be destroyed, 
    // but the copy in the heap (the vec) will
    // remain
    vec.push(foo); 
}

My usecase is indeed a little more complex. Passing a reference to a mutable vector fixes the first part of the problem, but then things are still tricky to me if I want to be able to add both objects owned from the outside and from the function scope

在这种情况下,您可以按照@Peter Hall 的建议使用Cow。它必须有变体 - 一个包含引用,一个包含拥有的值。

缺点是您的对象必须实现 Clone 特性。如果这不是一个选项,您可以轻松推出自己的 Cow 而无需该要求

#[derive(Clone)] // Objects must implement `Clone` in order to be used with `Cow`
pub struct Foo {
    pub integer: Box<u32>,
}

pub fn fill2<'a>(vec: &'a mut Vec<Cow<'a, Foo>>, foos: &'a Foos) {
    vec.push(Cow::Owned(Foo {
        integer: Box::new(1),
    }));

    for foo in &foos.foos {
        vec.push(Cow::Borrowed(foo));
    }
}