可变借用在getter中的生命周期不够长

3
pub type Data = i32;

pub struct Foo {
    data: Data,
}

impl Foo {
    pub fn data_mut(&mut self) -> &mut Data {
        &mut self.data
    }
}

pub struct Context {
    data: Data,
    foos: Vec<Foo>,
}

impl Context {
    pub fn broken(&mut self) -> &mut Data {
        // What are the lifetimes here that make this version not work?
        &mut self.foos.first_mut().unwrap().data_mut()
    }

    pub fn working(&mut self) -> &mut Data {
        &mut self.foos.first_mut().unwrap().data
    }
}

fn main() {}

(Playground)

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:21:14
   |
21 |         &mut self.foos.first_mut().unwrap().data_mut()
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
22 |     }
   |     - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/main.rs:19:5
   |
19 | /     pub fn broken(&mut self) -> &mut Data {
20 | |         // What are the lifetimes here that make this version not work?
21 | |         &mut self.foos.first_mut().unwrap().data_mut()
22 | |     }
   | |_____^

我不想将 data 字段设为公共的,所以我尝试使用一个 getter。我知道在 Rust 中 getter 的效果不佳,并且适当封装的集合不应该有可变的 get 方法,但这是我从另一种语言移植过来的代码,所以目前我没有进行任何重构(只是移植并覆盖测试)。那么其中的生命周期问题是什么?


1
我觉得这个问题很有趣,但是我认为代码可以被简化。 - Boiethios
@Boiethios 最小复现:https://play.rust-lang.org/?gist=3957938b4cd94f640624bfcc8adfc2ad&version=nightly&mode=debug&edition=2018 我也认为 NLL 会修复这段代码。 - Peter Hall
1
我无法确定它是否适用于您的原始大型代码,但是在您的游乐场示例中存在问题,因为您不需要&mut,因为data_mut已经返回了一个&mut Datahttps://play.rust-lang.org/?gist=b885337f7afd99e59ecb1bf62aaf2b3c&version=nightly&mode=debug&edition=2018 - loganfsmyth
哦,我的天啊。摊手. 是的,那个有效了。我已经习惯了在字段引用前加上 &mut,甚至也给getter返回值加上了前缀。等待将您的答案标记为最佳答案 - iwat0qs
所以,我现在理解的是,getter方法向调用者返回了一个正确的引用。在结果前加上&mut导致该结果变成了一个临时变量,代码试图返回对这个临时变量的引用,这在技术上是正确的,因为存在强制转换。 - iwat0qs
1个回答

2

随着

pub fn broken(&mut self) -> &mut Data {
    &mut self.foos.first_mut().unwrap().data_mut()
}

核心问题在于`data_mut()`的返回类型已经是一个`&mut Data`值,所以你实际上正在创建一个`&mut &mut Data`,尽管它会折叠。在你的情况下最简单的解决方法是完全删除`&mut`。
pub fn broken(&mut self) -> &mut Data {
    self.foos.first_mut().unwrap().data_mut()
}

似乎通过添加&mut会导致借用检查器创建临时位置,然后对该位置进行引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接