特征对象的{amp; mut和ref mut之间的差异

时间:2017-12-06 17:45:01

标签: rust traits mutable trait-objects

首先,我不会问&mutref mut本身之间的区别。

我问,因为我想:

let ref mut a = MyStruct

相同
let a = &mut MyStruct

考虑从函数返回特征对象。您可以返回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!");
    }
}

该方法收到一个可变参考用于演示目的。

这不会编译:

fn make_hello<'a>() -> &'a mut Hello {
    &mut English
}

也不是:

fn make_hello<'a>() -> &'a mut Hello {
    let b = &mut English;
    b
}

但这将编译并运作:

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

我的理论

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

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

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

上述所有内容都是一个不好的尝试,向我自己解释它为什么有效,但我没有基本面来证明它。

为什么会这样?

我也cross-posted this question to Reddit

1 个答案:

答案 0 :(得分:3)

This is a bug。我在下面的原始分析完全忽略了它返回 mutable 引用的事实。有关促销的内容仅在不可变值的上下文中有意义。

由于rules governing temporaries(强调我的)的细微差别,这是允许的:

  

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

参考继续:

  

当表达式可以写入表达式是最初写入的常量,借用和解除引用而不改变运行时行为时,会将rvalue表达式提升到'static插槽。也就是说,可以在编译时评估提升的表达式,并且结果值不包含内部可变性或析构函数(这些属性是根据可能的值确定的,例如&None始终具有类型{{1} },因为它包含任何不允许的东西)。

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

'static

至于为什么fn make_hello_3<'a>() -> &'a mut Hello { let ref mut b = English; let c: &'static mut Hello = b; c } 允许这样做而ref mut没有,我最好的猜测是&mut促销是尽力而为的,'static只是没有任何支票存在。您可能会查找或提交描述情况的问题。