我想用fill
函数范围内实例化的Foo
s填充Vec<Foo>
。这在生锈的情况下可能吗?我试着玩生命周期,但我不能在这个特定的用例中从教程/文档/样本中学到什么。
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)
的方法签名(没有借用)。然而,如果我这样做,我有一堆其他的问题。
游乐场
这不起作用,因为您正在推入对局部变量的引用,当方法结束时,这些引用将被销毁。如果像这样重写方法,会更容易理解:
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
但是在这种情况下,为什么会这样呢?
fn fill(mut vec: Vec<Foo>, foos: Foos)
它将有点工作,但在方法结束时,你的整个向量将被丢弃(deallocated),所以这个版本的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);
}
我的用例确实有点复杂。传递对可变向量的引用修复了问题的第一部分,但是如果我想要能够添加从外部和函数范围
拥有的对象,那么事情对我来说仍然很棘手。
在这种情况下,你可以使用Cow
作为@Peter Hall建议。它必须有两个变体——一个保存引用,一个保存已拥有的值。
缺点是你的对象必须实现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));
}
}