immutability - 在以下方法实现中,可变性如何影响 `self` 的生命周期?

标签 immutability rust lifetime

在下面的例子中,为什么 Bget_foos_mut 的实现给出了生命周期错误,而 get_foos 的实现工作正常?

trait Foo {
    fn get_foos<'a>(&'a self) -> Vec<&'a Foo> { Vec::new() }
    fn get_foos_mut<'a>(&'a mut self) -> Vec<&'a mut Foo> { Vec::new() }
    fn hello(&self) { println!("Hello!") }
}

struct A { i: int }
impl Foo for A { fn hello(&self) { println!("Hello {}!", self.i) } }

struct B { foos: Vec<A> }
impl Foo for B {
    fn get_foos<'a>(&'a self) -> Vec<&'a Foo> {
        Vec::from_fn(self.foos.len(), |i| self.foos.get(i) as &Foo) // This is fine.
    }
    fn get_foos_mut<'a>(&'a mut self) -> Vec<&'a mut Foo> {
        Vec::from_fn(self.foos.len(), |i| self.foos.get_mut(i) as &mut Foo) // This gives an error?
    }
}

fn main() {
    let b = B { foos: vec![A { i: 1 }] };
    for foo in b.get_foos().iter() {
        foo.hello();
    }
}

这是围栏给出的错误:

<anon>:17:43: 17:52 error: lifetime of `self` is too short to guarantee its contents can be safely reborrowed
<anon>:17         Vec::from_fn(self.foos.len(), |i| self.foos.get_mut(i) as &mut Foo)
                                                    ^~~~~~~~~
<anon>:16:59: 18:6 note: `self` would have to be valid for the lifetime 'a as defined on the block at 16:58...
<anon>:16     fn get_foos_mut<'a>(&'a mut self) -> Vec<&'a mut Foo> {
<anon>:17         Vec::from_fn(self.foos.len(), |i| self.foos.get_mut(i) as &mut Foo)
<anon>:18     }
<anon>:17:9: 17:76 note: ...but `self` is only valid for the call at 17:8
<anon>:17         Vec::from_fn(self.foos.len(), |i| self.foos.get_mut(i) as &mut Foo)
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

注意:我注意到 Bget_foos_mut 如果这样写就可以工作:

fn get_foos_mut<'a>(&'a mut self) -> Vec<&'a mut Foo> {
    let mut vec: Vec<&'a mut Foo> = Vec::with_capacity(self.foos.len());
    for foo in self.foos.mut_iter() { vec.push(foo); }
    vec
}

为什么实现在这种情况下有效,而不是在上面的 Vec::from_fn(...) 版本中?

最佳答案

&mut 指针必须是无别名的,也就是说,如果您想通过 进行变异,则不能有其他引用/指针/路径可以用来读取/写入数据&mut。当您调用 self.foos.get_mut(i) 时,get_mut 对编译器来说就像一个黑匣子,它无法判断借用了哪些数据,因此它由于签名(通过生命周期将返回值连接到 self 对象),必须假设整个 Vec 是借用的

fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T

否则有人可以制作别名 &mut 指针:例如

let a = self.foos.get_mut(0);
let b = self.foos.get_mut(0);

The mut_iter implementation内部使用了unsafe,但是仔细写了一个安全的接口(interface),就是没有办法使用mut_iter来获取aliasing &mut指针(没有 unsafe),因为它按顺序只产生每个可变引用一次。

FWIW,我会将这些方法写成 self.foos.iter().map(|x| x as &Foo).collect()self.foos.mut_iter() .map(|x| x as &mut Foo).collect() 而不是显式的 pushfrom_fn

关于immutability - 在以下方法实现中,可变性如何影响 `self` 的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24750369/

相关文章:

java - 字符串是不可变的——这意味着我不应该使用 += 而只使用 StringBuffer?

c# - 不可变数据结构和并发

rust - 如何为关联常量在 Self 上设置显式生命周期?

rust - 使结构比赋予该结构的方法的参数更长寿

java - 需要不可变类属性与私有(private)属性一起成为最终属性

java - 关于不可变类防御性复制

profiling - Rust 编译器有分析选项吗?

multidimensional-array - 有没有一种好方法可以在使用rust 的 ndarray 中进行重叠复制?

rust - 在 Rust 中实现 Fn(&something) 的特征

rust - 为什么不能在同一结构中存储值和对该值的引用?