【问题标题】:Why can't I mutably borrow a primitive from an enum?为什么我不能从枚举中可变地借用一个原语?
【发布时间】:2017-10-20 17:36:25
【问题描述】:

我希望能够在 Foo 枚举中获得对 usize 的引用(不可变和可变):

use Foo::*;

#[derive(Debug, PartialEq, Clone)]
pub enum Foo {
    Bar(usize)
}

impl Foo {
    /* this works */
    fn get_bar_ref(&self) -> &usize {
        match *self {
            Bar(ref n) => &n
        }
    }

    /* this doesn't */
    fn get_bar_ref_mut(&mut self) -> &mut usize {
        match *self {
            Bar(ref mut n) => &mut n
        }
    }
}

但我无法获得可变引用,因为:

n 寿命不够长

我能够提供访问Foo 的其他内容的类似函数的两种变体Boxed - 为什么可变借用(以及为什么只有它)会因未装箱的原语而失败?

【问题讨论】:

    标签: enums rust borrow-checker


    【解决方案1】:

    这些示例显示了示例问题:

    fn implicit_reborrow<T>(x: &mut T) -> &mut T {
        x
    }
    
    fn explicit_reborrow<T>(x: &mut T) -> &mut T {
        &mut *x
    }
    
    fn implicit_reborrow_bad<T>(x: &mut T) -> &mut T {
        &mut x
    }
    
    fn explicit_reborrow_bad<T>(x: &mut T) -> &mut T {
        &mut **&mut x
    }
    

    explicit_ 版本显示了编译器通过deref coercions 推断出的内容。
    _bad 版本都以完全相同的方式出错,而其他两个版本可以编译。

    这要么是一个错误,要么是当前在编译器中实现生命周期的方式的限制。 &amp;mut T 相对于 T 的不变性 可能 与它有关,因为它导致 &amp;mut &amp;'a mut T 相对于 'a 是不变的,因此在期间 更具限制性比共享引用 (&amp;&amp;'a T) 的情况进行推理,即使在这种情况下严格性是不必要的。

    【讨论】:

      【解决方案2】:

      您需要将Bar(ref mut n) =&gt; &amp;mut n 替换为Bar(ref mut n) =&gt; n

      当你在Bar(ref mut n) 中使用ref mut n 时,它会创建一个可变的 引用Bar中的数据,所以n的类型为&amp;mut usize。 然后你尝试返回&amp;mut n&amp;mut &amp;mut u32 类型。

      这部分很可能不正确。

      现在deref coercion 加入 并将&amp;mut n 转换为&amp;mut *n,创建一个临时值*n usize 类型的,寿命不够长。

      【讨论】:

      • 这还是很奇怪。为什么get_bar_ref 的行为不一样?
      • 有趣。根据文档&amp;Bar(ref n) =&gt; &amp;n 应该扩展为&amp;Bar(ref n) =&gt; &amp;*(n.deref()),但它不会编译。我想这涉及到一些编译器魔法。
      • 我认为这与 deref 强制无关。
      • 解除引用强制不可能创建临时对象。正在发生的事情是 &amp;mut **&amp;mut n(这是 deref 强制在该示例中有效导致的结果)和 &amp;mut *n确实起作用)之间的差异。不太可能需要健全性(因为两个版本都执行 完全相同 操作),但由于可变引用下的不变性,生命周期可能会比应有的“收紧”更多。现在找不到,但可能之前已经报告过这个问题。
      • @ljedrz 如果你有Foo(ref boxed),那么*boxed: Box&lt;T&gt;**boxed: T,所以&amp;**boxed: &amp;T但是boxed: &amp;Box&lt;T&gt; 会很乐意强制转换为 &amp;T(通过 deref 强制转换)。 &amp;*boxed: &amp;Box&lt;T&gt; 相当于简单地使用boxed
      猜你喜欢
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 2013-02-11
      相关资源
      最近更新 更多