简体   繁体   English

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

[英]Difference between &mut and ref mut for trait objects

First of all, I'm not asking what's the difference between &mut and ref mut per se. 首先,我不是要问&mutref mut本身有什么区别。

I'm asking because I thought: 我在问,因为我想:

let ref mut a = MyStruct

is the same as 是相同的

let a = &mut MyStruct

Consider returning a trait object from a function. 考虑从函数返回特征对象。 You can return a Box<Trait> or a &Trait . 您可以返回Box<Trait>&Trait If you want to have mutable access to its methods, is it possible to return &mut Trait ? 如果你想对它的方法进行可变访问,是否可以返回&mut Trait

Given this example: 鉴于这个例子:

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!");
    }
}

The method receives a mutable reference for demonstration purposes. 该方法接收可变参考用于演示目的。

This won't compile: 这不会编译:

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

nor this: 也不是这样

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

But this will compile and work: 但这将编译和工作:

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

My theory 我的理论

This example will work out of the box with immutable references (not necessary to assign it to a variable, just return &English ) but not with mutable references. 这个例子将使用不可变引用开箱即用(不必将它分配给变量,只返回&English ),但不能使用可变引用。 I think this is due to the rule that there can be only one mutable reference or as many immutable as you want. 我认为这是因为规则只能有一个可变引用或者你想要的多个不可变引用。

In the case of immutable references, you are creating an object and borrowing it as a return expression; 在不可变引用的情况下,您正在创建一个对象并将其作为返回表达式借用; its reference won't die because it's being borrowed. 它的参考不会因为被借用而死亡。

In the case of mutable references, if you try to create an object and borrow it mutably as a return expression you have two mutable references (the created object and its mutable reference). 在可变引用的情况下,如果您尝试创建一个对象并将其作为返回表达式可变地借用,则您有两个可变引用(创建的对象及其可变引用)。 Since you cannot have two mutable references to the same object it won't perform the second, hence the variable won't live long enough. 由于您不能对同一个对象进行两次可变引用,因此它不会执行第二次,因此该变量的生存时间不够长。 I think that when you write let mut ref b = English and return b you are moving the mutable reference because it was captured by a pattern. 我认为当你写的时候let mut ref b = English并返回b你正在移动可变参考,因为它是由模式捕获的。

All of the above is a poor attempt to explain to myself why it works, but I don't have the fundamentals to prove it. 以上所有都是一个不好的尝试向我自己解释它为什么有效,但我没有基本的证据来证明它。

Why does this happen? 为什么会这样?

I've also cross-posted this question to Reddit . 我也将这个问题交叉发布给了Reddit

This is a bug . 这是一个错误 My original analysis below completely ignored the fact that it was returning a mutable reference. 我在下面的原始分析完全忽略了它返回一个可变参考的事实。 The bits about promotion only make sense in the context of immutable values. 关于促销的内容只在不可变值的上下文中才有意义。


This is allowable due to a nuance of the rules governing temporaries (emphasis mine): 由于管理临时工作的规则的细微差别(强调我的),这是允许的:

When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead, if not promoted to 'static . 在大多数左值上下文中使用rvalue时,会创建一个临时的未命名左值,而不是将其提升为'static

The reference continues: 参考继续:

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. 当表达式可以写入表达式最初写入的常量,借用和解除引用而不改变运行时行为时,会将rvalue表达式提升为'static'static 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, eg &None always has the type &'static Option<_> , as it contains nothing disallowed). 也就是说,可以在编译时评估提升的表达式,并且结果值不包含内部可变性或析构函数(这些属性是根据可能的值确定的,例如&None始终具有类型&'static Option<_> ,因为它包含任何不允许的东西)。

Your third case can be rewritten as this to "prove" that the 'static promotion is occurring: 您的第三个案例可以重写为“证明” 'static促销正在发生:

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

As for why ref mut allows this and &mut doesn't, my best guess is that the 'static promotion is on a best-effort basis and &mut just isn't caught by whatever checks are present. 至于为什么ref mut允许这个而且&mut没有,我最好的猜测是'static促销是在尽力而为的基础上并且&mut就不会被任何检查所捕获。 You could probably look for or file an issue describing the situation. 您可能会查找或提交描述情况的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在“if let Some(ref mut x) = option”和“if let Some(x) = option.as_mut()”中匹配可变选项引用有什么区别? - What is the difference between matching a mutable Option reference in “if let Some(ref mut x) = option” and in “if let Some(x) = option.as_mut()”? 分配* mut T和&mut T有什么区别? - What's the difference between assigning to a *mut T and a &mut T? &amp;mut unsafe { } 和 unsafe { &amp;mut } 有什么区别? - What's the difference between &mut unsafe { } and unsafe { &mut }? `&amp;mut retval` 和 `retval as *const T as *mut T` 有什么区别? - What is the difference between `&mut retval` and `retval as *const T as *mut T`? 将 &amp;self 转换为 mut(在不是 mut 的地方使用预定义的特征) - Cast &self to mut (to use predefined trait where it isn't mut) 为什么&mut&foo有效,而&mut a_ref_to_foo无效? - Why is `&mut &foo` valid but `&mut a_ref_to_foo` is invalid? 将“mut”放在变量名之前和“:”之后有什么区别? - What's the difference between placing "mut" before a variable name and after the ":"? RefCell上borrow_mut的区别 <X> 和RefCell &lt;&X&gt; - Difference between borrow_mut on a RefCell<X> and RefCell<&X> 为结构创建* mut * mut - Create *mut *mut to a struct 在“ get_trait_mut”中返回对特征的可变引用 - Returning mutable reference to trait in “get_trait_mut”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM