首先,我不会问&mut
和ref 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
时,你移动可变引用,因为它是由模式捕获的。
上述所有内容都是一个不好的尝试,向我自己解释它为什么有效,但我没有基本面来证明它。
为什么会这样?
答案 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
只是没有任何支票存在。您可能会查找或提交描述情况的问题。