我有以下对象:
#[derive(Debug)]
struct Bar(pub i32);
#[derive(Debug)]
struct Foo {
pub bars: Vec<Bar>
}
假设我在拥有Foo
的环境中,我可以移动该字段:
for x in foo.bars { /* ... */ }
或者我可以通过参考
使用它for x in &foo.bars { /* ... */ }
但是,我想动态加载Vec<Bar>
(例如,从数据库中加载),我可能会这样:
#[derive(Debug)]
struct Bar(pub i32);
#[derive(Debug)]
struct Foo {
pub __bars: Option<Vec<Bar>>
}
impl Foo {
pub fn bars<'a>(&'a mut self) -> &'a Vec<Bar> {
if self.__bars.is_none() {
// load data here
self.__bars = Some(Vec::new());
}
self.__bars.as_ref().unwrap()
}
}
但是现在我无法移动那个领域(即使我拥有该结构)。两个
for x in *foo.bars() { }
和
for x in foo.bars() { let y = *x; }
给我一个cannot move out of borrowed content
错误。
我可以这样做:
impl Foo
pub fn load_bars(&mut self) {
if self.__bars.is_none() {
// load data here
self.__bars = Some(Vec::new());
}
}
}
let foo = Foo { /* ... */ };
foo.load_bars();
for x in foo.__bars.unwrap() { }
但这种情况更少&#34;愉快&#34;是否有一些特殊的引用类型,我可以从我的bars
函数返回,这将允许我在以后需要时移动它(并且可以)?
答案 0 :(得分:3)
是否有一些特殊的引用类型,我可以从我的bar函数返回,让我移动它
这两个概念是不兼容的。引用指向内存中的位置。移动值时,将更改其在内存中的位置,使任何引用无效。访问旧引用会导致内存不安全,因此Rust会阻止它。
我只是创建另一种解构类型的方法:
fn bars2(mut self) -> Vec<Bar> {
self.bars();
self.bars.expect("Impossible, we just ensured it was there")
}
然后,当您希望获得所有权时,您可以使用此方法:
fn main() {
let mut foo = Foo { bars: None };
for x in foo.bars() {
// by ref
}
for x in foo.bars2() {
// by value
}
}
在这个的情况下,这个工作原理是一样的,因为结构中只有一个字段。将值移入bars2
并将向量移出self
后,原始结构中没有任何内容可以获取!
如果您确实有多个值,则可以扩展该方法以返回包含每个值的元组:
fn bars2(mut self) -> (Vec<Bar>, String) {
self.bars();
let b = self.bars.expect("Impossible, we just ensured it was there");
(b, self.owned_name)
}
或者如果您不关心许多其他值,您只需take
一个值:
fn bars2(&mut self) -> Vec<Bar> {
self.bars();
self.bars.take().expect("Impossible, we just ensured it was there")
}
请注意,这只需要&mut self
并将self.bars
作为None
。在其他情况下,可能会使用Option
,mem::swap
或mem::replace
。
此外:
fn bars
上不需要任何明确的生命周期。&[T]
而不是&Vec<T>
,因为它会更好地隐藏内部实施。