如何在Rust中解释对可变类型的不可变引用? [英] How to interpret immutable references to mutable types in Rust?

查看:261
本文介绍了如何在Rust中解释对可变类型的不可变引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的取消引用链中存在任何个不可变的引用,则似乎无法对任何内容进行突变.样本:

It seems that I cannot mutate anything if there is any immutable reference in my chain of dereferencing. A sample:

fn main() {
    let mut x = 42;
    let y: &mut i32 = &mut x; // first layer
    let z: &&mut i32 = &y; // second layer
    **z = 100; // Attempt to change `x`, gives compiler error.

    println!("Value is: {}", z);
}

我遇到了编译器错误:

error[E0594]: cannot assign to `**z` which is behind a `&` reference
 --> src/main.rs:5:5
  |
4 |     let z: &&mut i32 = &y; // second layer
  |                        -- help: consider changing this to be a mutable reference: `&mut y`
5 |     **z = 100; // Attempt to change `x`, gives compiler error.
  |     ^^^^^^^^^ `z` is a `&` reference, so the data it refers to cannot be written

从某种意义上讲,这是有道理的,否则编译器将无法防止对同一变量具有多个可变的访问路径.

In some way, this makes sense, as otherwise the compiler would not be able to prevent having multiple mutable access paths to the same variable.

但是,在查看类型时,语义似乎是违反直觉的:

However, when looking at the types, the semantics seem to be counter-intuitive:

  • 变量y具有类型&mut i32,或用简单的英语对整数的可变引用".
  • 变量z的类型为&&mut i32,或者用简单的英语对可变整数的引用是不可变的".
  • 通过一次取消引用z(即*z),我将得到类型为&mut i32的东西,即具有与y相同类型的东西.但是,再次引用此 (即**z)会得到类型为i32的某种东西,但不允许我对该整数进行突变.
  • Variable y has type &mut i32, or in plain English "A mutable reference to an integer".
  • Variable z has type &&mut i32, or in plain English "An immutable reference to a mutable reference to an integer".
  • By dereferencing z once (i.e. *z) I will get something of type &mut i32, i.e. something of the same type as y. However, dereferencing this again (i.e. **z) gets me something of type i32, but I am not allowed to mutate that integer.

从本质上讲,某种程度上的引用对我来说是谎言,因为它们实际上并没有执行他们声称的操作.在这种情况下,我应该如何正确阅读引用类型,或者还应该如何恢复对该概念的信任?

In essence, the types of references in some sense lie to me, as they don't actually do what they claim they do. How should I read types of references properly in this case, or how else can I restore faith in that concept?

对此示例进行测试:

fn main() {
    let mut x = 42;
    let y: &mut i32 = &mut x; // first layer
    let m: &&mut i32 = &y; // second layer
    let z: &&&mut i32 = &m; // third layer
    compiler_builtin_deref_first_layer(*z);
}

fn compiler_builtin_deref_first_layer(v: &&mut i32) {
    compiler_builtin_deref_second_layer(*v);
}

fn compiler_builtin_deref_second_layer(w: &mut i32) {
    println!("Value is: {}", w);
}

最后两个函数的参数类型正确.如果我更改其中任何一个,编译器都会抱怨类型不匹配.但是,如果按原样编译示例,则会出现此错误:

The parameter types of those last two functions are correct. If I change any of those, the compiler will complain about mismatched types. However, if I compile the example as-is, I get this error:

error[E0596]: cannot borrow `**v` as mutable, as it is behind a `&` reference

以某种方式,对compiler_builtin_deref_first_layer的调用似乎还可以,但对compiler_builtin_deref_second_layer的调用却不行.编译器错误涉及**v,但是我只看到一个*v.

Somehow, the call to compiler_builtin_deref_first_layer seems to be okay, but the call to compiler_builtin_deref_second_layer isn't. The compiler error talks about **v, but I only see a *v.

推荐答案

从本质上讲,某种程度上的引用对我来说是谎言,因为它们实际上并没有执行他们声称的操作.在这种情况下,我应该如何正确阅读引用类型,或者还应该如何恢复对该概念的信任?

In essence, the types of references in some sense lie to me, as they don't actually do what they claim they do. How should I read types of references properly in this case, or how else can I restore faith in that concept?

在Rust中读取引用的正确方法是获得权限.

The right way to read references in Rust is as permissions.

如果不借用对象的所有权,则授予您对对象执行任何操作的权限;创建,销毁它,然后将其从一个地方移到另一个地方.您是所有者,可以执行您想做的事情,可以控制该对象的寿命.

Ownership of an object, when it's not borrowed, gives you permission to do whatever you want to the object; create it, destroy it, move it from one place to another. You are the owner, you can do what you want, you control the life of that object.

可变引用从所有者那里借用了对象.当可变引用处于活动状态时,它会授予对该对象的独占访问权限.没有人可以读取,写入对象或对该对象执行任何其他操作.可变引用也可以是调用和排他引用,或排他借用.您必须将对象的控制权交还给原始所有者,但与此同时,您可以使用该对象做任何想做的事情.

A mutable reference borrows the object from the owner. While the mutable reference is alive, it grants exclusive access to the object. No one else can read, write, or do anything else to the object. A mutable reference could also be call and exclusive reference, or exclusive borrow. You have to return control of the object back to the original owner, but in the meantime, you get to do whatever you want with it.

不可变的引用或共享借用意味着您可以与其他人同时访问它.因此,您只能阅读它,而没有人可以对其进行修改,否则将根据操作发生的确切顺序产生不确定的结果.

An immutable reference, or shared borrow, means you get to access it at the same time as others. Because of that, you can only read it, and no one can modify it, or there would be undefined results based on the exact order that the actions happened in.

可以对拥有的对象进行可变(或排他)引用和不可变(或共享)引用,但这并不意味着您通过引用引用该对象时便拥有该对象.您可以通过哪种引用来限制对象的操作范围.

Both mutable (or exclusive) references and immutable (or shared) references can be made to owned objects, but that doesn't mean that you own the object when you're referring to it through the reference. What you can do with an object is constrained by what kind of reference you're reaching it through.

因此,请勿将&&mut T引用视为对T的可变引用的不可变引用",然后再考虑嗯,我不能更改外部引用,但我应该能够对内部参考."

So don't think of an &&mut T reference as "an immutable reference to a mutable reference to T", and then think "well, I can't mutate the outer reference, but I should be able to mutate the inner reference."

而是将其视为某人拥有T.他们已经授予了独占访问权,所以现在有人有权修改T.但是与此同时,该人已经赋予了共享对&mut T的访问,这意味着他们已承诺在一段时间内不会对其进行更改,并且所有用户都可以使用对&mut T的共享引用,包括对基础T的引用取消引用,但仅对于您通常可以使用共享参考进行的操作,这意味着可以阅读但不能写作."

Instead, think of it as "Someone owns a T. They've given out exclusive access, so right now there's someone who has the right to modify the T. But in the meantime, that person has given out shared access to the &mut T, which means they've promised to not mutate it for a period of time, and all of the users can use the shared reference to &mut T, including dereferencing to the underlying T but only for things which you can normally do with a shared reference, which means reading but not writing."

最后要记住的是,可变或不可变部分实际上并不是引用之间的根本区别.实际上,这是排他性与共享性的一部分.在Rust中,您可以通过共享引用进行修改,只要有某种内部保护机制可以确保一次只有一个人这样做.可以采用多种方式,例如CellRefCellMutex.

The final thing to keep in mind is that the mutable or immutable part aren't actually the fundamental difference between the references. It's really the exclusive vs. shared part that are. In Rust, you can modify something through a shared reference, as long as there is some kind of inner protection mechanism that ensures that only one person does so at a time. There are multiple ways of doing that, such as Cell, RefCell, or Mutex.

所以&T&mut T所提供的并不是真正的不变或可变的访问,尽管它们如此命名是因为这是它们在没有任何库功能的情况下在语言级别提供的默认访问级别.但是,它们真正提供的是共享访问或互斥访问,然后,数据类型的方法可以根据调用者是拥有值,专有引用还是共享引用来为调用者提供不同的功能.

So what &T and &mut T provide isn't really immutable or mutable access, though they are named as such because that's the default level of access they provide at the language level in the absence of any library features. But what they really provide is shared or exclusive access, and then methods on data types can provide different functionality to callers depending on whether they take an owned value, an exclusive reference, or a shared reference.

因此,将引用视为权限;这是您通过参考获得的东西,它决定了您可以使用它进行的操作.而且,当您拥有所有权或排他性引用时,暂时提供排他性或共享引用会阻止您在那些借来的引用仍然存在的情况下可变地访问对象.

So think of references as permissions; and it's the reference that you reach something through that determines what you are allowed to do with it. And when you have ownership or an exclusive reference, giving out an exclusive or shared reference temporarily prevents you from mutably accessing the object while those borrowed references are still alive.

这篇关于如何在Rust中解释对可变类型的不可变引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆