特征对象的&mut和ref mut之间的区别

Rod*_*una 7 mutable traits rust trait-objects

首先,我不是问&mutref mut本身有什么区别.

我在问,因为我想:

let ref mut a = MyStruct
Run Code Online (Sandbox Code Playgroud)

是相同的

let a = &mut MyStruct
Run Code Online (Sandbox Code Playgroud)

考虑从函数返回特征对象.你可以退还一个Box<Trait>或一个&Trait.如果您希望对其方法进行可变访问,是否可以返回&mut Trait

鉴于这个例子:

trait Hello {
    fn hello(&mut self);
}

struct English;
struct Spanish;

impl Hello for English {
    fn hello(&mut self) {
        println!("Hello!");
    }
}

impl Hello for Spanish {
    fn hello(&mut self) {
        println!("Hola!");
    }
}
Run Code Online (Sandbox Code Playgroud)

该方法接收可变参考用于演示目的.

这不会编译:

fn make_hello<'a>() -> &'a mut Hello {
    &mut English
}
Run Code Online (Sandbox Code Playgroud)

也不是这样

fn make_hello<'a>() -> &'a mut Hello {
    let b = &mut English;
    b
}
Run Code Online (Sandbox Code Playgroud)

但这将编译和工作:

fn make_hello<'a>() -> &'a mut Hello {
    let ref mut b = English;
    b
}
Run Code Online (Sandbox Code Playgroud)

我的理论

这个例子将开箱即用,带有不可变引用(不需要将它分配给变量,只返回&English),但不能使用可变引用.我认为这是因为规则只能有一个可变引用或者你想要的不可变引用.

在不可变引用的情况下,您正在创建一个对象并将其作为返回表达式借用; 它的参考不会因为被借用而死亡.

在可变引用的情况下,如果您尝试创建一个对象并将其作为返回表达式可变地借用,则您有两个可变引用(创建的对象及其可变引用).由于您不能对同一个对象进行两次可变引用,因此它不会执行第二次,因此该变量的生存时间不够长.我认为当你编写let mut ref b = English并返回时,b你正在移动可变参考,因为它是由模式捕获的.

以上所有都是一个不好的尝试向我自己解释它为什么有效,但我没有基本的证据来证明它.

为什么会这样?

我也将这个问题交叉发布给了Reddit.

She*_*ter 4

这是一个错误我下面的原始分析完全忽略了它返回可变引用的事实。有关晋升的内容只有在价值观不变的情况下才有意义。


这是允许的,因为管理临时人员的规则存在细微差别(重点是我的):

在大多数左值上下文中使用右值时,如果未提升'static为 ,则会创建并使用临时的未命名左值。

参考文献继续:

当表达式'static可以用常量、借用和取消引用借用表达式最初写入的位置而不改变运行时行为时,就会将右值表达式提升到槽。也就是说,提升的表达式可以在编译时求值,并且结果值不包含内部可变性或析构函数(这些属性是根据可能的值确定的,例如&None始终具有类型&'static Option<_>,因为它不包含任何不允许的内容)。

您的第三个案例可以重写为“证明”促销'static正在发生:

fn make_hello_3<'a>() -> &'a mut Hello {
    let ref mut b = English;
    let c: &'static mut Hello = b;
    c
}
Run Code Online (Sandbox Code Playgroud)

至于为什么ref mut允许或&mut不允许这样做,我最好的猜测是,'static促销是在尽最大努力的基础上进行的,&mut只是没有被任何支票所捕获。您可能可以查找或提交描述情况的问题。