特征对象的 &mut 和 ref mut 之间的区别
Difference between &mut and ref mut for trait objects
首先,我不是在问 &mut
和 ref mut
本身有什么区别。
我问是因为我认为:
let ref mut a = MyStruct
与
相同
let a = &mut MyStruct
考虑return从函数中获取特征对象。您可以 return 一个 Box<Trait>
或一个 &Trait
。如果你想对其方法进行可变访问,是否可以 return &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
}
我的理论
此示例将开箱即用地使用不可变引用(无需将其分配给变量,只需 return &English
),但不适用于可变引用。我认为这是由于规则,即只能有一个可变引用或任意多个不可变引用。
在不可变引用的情况下,您正在创建一个对象并将其借用为 return 表达式;它的引用不会因为被借用而消失。
在可变引用的情况下,如果您尝试创建一个对象并将其作为 return 表达式可变地借用,您将有两个可变引用(创建的对象及其可变引用)。由于您不能对同一个对象有两个可变引用,因此它不会执行第二个,因此该变量不会存在足够长的时间。我认为当您编写 let mut ref b = English
和 return b
时,您是在 移动 可变引用,因为它被模式捕获。
以上所有内容都不足以向我自己解释它为何有效,但我没有基本原理来证明它。
为什么会这样?
This is a bug。我下面的原始分析完全忽略了它返回 mutable 引用这一事实。有关提升的位仅在 不可变 值的上下文中才有意义。
由于 rules governing temporaries(强调我的)的细微差别,这是允许的:
When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead, if not promoted to 'static
.
引用继续:
Promotion of an rvalue expression to a 'static
slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was the originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None
always has the type &'static Option<_>
, as it contains nothing disallowed).
您的第三个案例可以重写为 "prove" 正在发生 '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
促销是在尽力而为的基础上 &mut
只是没有被存在的任何支票抓住。您可能会查找或提交描述情况的问题。
首先,我不是在问 &mut
和 ref mut
本身有什么区别。
我问是因为我认为:
let ref mut a = MyStruct
与
相同let a = &mut MyStruct
考虑return从函数中获取特征对象。您可以 return 一个 Box<Trait>
或一个 &Trait
。如果你想对其方法进行可变访问,是否可以 return &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
}
我的理论
此示例将开箱即用地使用不可变引用(无需将其分配给变量,只需 return &English
),但不适用于可变引用。我认为这是由于规则,即只能有一个可变引用或任意多个不可变引用。
在不可变引用的情况下,您正在创建一个对象并将其借用为 return 表达式;它的引用不会因为被借用而消失。
在可变引用的情况下,如果您尝试创建一个对象并将其作为 return 表达式可变地借用,您将有两个可变引用(创建的对象及其可变引用)。由于您不能对同一个对象有两个可变引用,因此它不会执行第二个,因此该变量不会存在足够长的时间。我认为当您编写 let mut ref b = English
和 return b
时,您是在 移动 可变引用,因为它被模式捕获。
以上所有内容都不足以向我自己解释它为何有效,但我没有基本原理来证明它。
为什么会这样?
This is a bug。我下面的原始分析完全忽略了它返回 mutable 引用这一事实。有关提升的位仅在 不可变 值的上下文中才有意义。
由于 rules governing temporaries(强调我的)的细微差别,这是允许的:
When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead, if not promoted to
'static
.
引用继续:
Promotion of an rvalue expression to a
'static
slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was the originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g.&None
always has the type&'static Option<_>
, as it contains nothing disallowed).
您的第三个案例可以重写为 "prove" 正在发生 '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
促销是在尽力而为的基础上 &mut
只是没有被存在的任何支票抓住。您可能会查找或提交描述情况的问题。