为什么我不能从枚举中可变地借用基本类型?

9

我希望能够获取到在Foo枚举中被包裹在Bar中的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 中其他被 Box 包装的内容的类似功能的两个变体 - 为什么对于一个未包装的原始类型,可变借用会失败(为什么只有它)?
2个回答

8
您需要将Bar(ref mut n) => &mut n替换为Bar(ref mut n) => n
当您在Bar(ref mut n)中使用ref mut n时,它会创建对Bar中数据的可变引用,因此n的类型是&mut usize。然后您尝试返回&mut n的类型是&mut &mut u32

这部分内容很可能是不正确的。

现在解引用强制转换开始起作用,将&mut n转换为&mut *n,创建临时值*n,其类型为usize,但其寿命不够长。


2
这仍然很奇怪。为什么get_bar_ref的行为不同呢? - Peter Hall
1
有趣。根据文档,&Bar(ref n) => &n 应该扩展为 &Bar(ref n) => &*(n.deref()),但它无法编译。我想这里涉及到一些编译器的魔法。 - red75prime
2
我不相信这与解引用强制转换有任何关系。 - Shepmaster
4
Deref coercion(解引用强制转换)不可能创建临时对象。正在发生的事情是 &mut **&mut n&mut *n 之间的差异(前者是解引用强制转换在该示例中的实际结果),因为可变引用的不变性,它不太可能是必需的安全性要求(因为两个版本执行的操作完全相同),但是寿命可能会比应该的更“紧密”。我现在找不到它了,但这个问题可能已经被报告过了。 - eddyb
2
如果你有Foo(ref boxed),那么*boxed: Box<T>**boxed: T,所以&**boxed: &T然而boxed: &Box<T>会通过解引用强制转换愉快地转换为&T&*boxed: &Box<T>等同于简单地使用boxed - eddyb
显示剩余3条评论

7

以下示例展示了样本问题:

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版本以完全相同的方式出现错误,而其他两个版本可以编译。
这可能是编译器当前实现生命周期时存在的bug或限制。 &mut T对于T的不变性可能与此有关,因为它导致&mut &'a mut T'a上是不变的,因此在推断期间比共享引用(&&'a T)情况下更加限制,即使在这种情况下严格性也是不必要的。

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