【问题标题】:cannot assign to `*x` because it is borrowed不能分配给`*x`,因为它是借来的
【发布时间】:2022-11-08 20:00:27
【问题描述】:

我的错误代码 sn-p 和编译器错误信息:

// code snippet 1:

0 fn main() {
1     let mut x: Box<i32> = Box::new(4);
2     let r: &Box<i32> = &x;
3     *x = 8;
4     println!("{}", r);
5 }
// compiler error info: 

error[E0506]: cannot assign to `*x` because it is borrowed
 --> src/main.rs:3:4
  |
2 |     let r = &x;
  |             -- borrow of `*x` occurs here
3 |     *x = 8;
  |     ^^^^^^ assignment to borrowed `*x` occurs here
4 |     println!("{}", r);
  |                    - borrow later used here

For more information about this error, try `rustc --explain E0506`.

以下代码无法编译,这对我来说很有意义,因为我们不能使引用 r 无效。

// code snippet 2:

0 fn main() {
1     let mut x: i32 = 0;
2     let r: &i32 = &x;
3     x = 1;
4     println!("{}", r);
5 }

但是code snippet1compiler error info 对我来说没有多大意义。

x 是堆栈上的指针,指向堆内存段,其内容为 4 ,引用 r 仅借用 x (指针不是堆内存段),而在第 3 行 *x = 8; ,什么我们在这里所做的就是改变堆上的内存(而不是栈上的指针)。更改发生在堆上,而引用仅与堆栈相关,它们不相互关联。

这个问题有点挑衅,但我不是为了争论而争论。

如果您发现我的问题不正常,请随时指出:)

【问题讨论】:

    标签: pointers rust lifetime borrow-checker


    【解决方案1】:

    更改发生在堆上,而引用仅与堆栈相关,它们不相互关联。

    没关系,因为类型系统不适用于信息的“深度”。

    就它而言,借用x 是借用整个x 到任意深度,因此禁止x 内部的任何更改。

    出于类型检查的目的,这是没有区别如果xBox&lt;Vec&lt;_&gt;&gt;,并且r 被积极用于迭代,则导致对内部向量的任何更新都可能使迭代器无效。

    (在类型方面*x = 8 确实需要首先对盒子本身进行唯一引用,然后再将其“升级”为对盒子内容的唯一引用,正如您从 the trait implementation 中看到的那样)

    【讨论】:

      【解决方案2】:

      Rust 的整个借用模型强制执行一个简单的要求:一个内存位置的内容只有在只有一个可以访问该位置的指针时才能被改变。

      在您的情况下,您尝试改变的堆位置可以通过xr 访问,因此拒绝改变。

      该模型使编译器能够执行积极的优化,例如,允许通过寄存器和/或缓存中的别名存储可访问的值,而无需在读取值时再次从内存中获取。

      【讨论】:

        【解决方案3】:

        * 的语义由两个特征决定:

        pub trait Deref {
           type Target: ?Sized;
           fn deref(&self) -> &Self::Target;
        }
        

        或者

        pub trait DerefMut: Deref {
           fn deref_mut(&mut self) -> &mut Self::Target;
        }
        

        在您的情况下,当您编写 *x = 8 时,Rust 编译器会将表达式扩展为调用 DerefMut::deref_mut(&amp;mut x),因为Box&lt;T&gt; 实现了Deref&lt;Target=T&gt;DerefMut。这就是为什么在*x = 8 行中执行x 的可变借用,并且根据孤儿规则它不能完成,因为我们已经在let r: &amp;Box&lt;i32&gt; = &amp;x; 中借用了x

        【讨论】:

          【解决方案4】:

          我刚刚从 Programming Rust (Version 2) 中找到了一个很棒的图表,它确实很好地回答了我的问题:

          就我的问题而言,当xr 共享引用时,x 的所有权树中的所有内容(堆栈指针和堆内存段)变为只读。

          我知道 Stack Overflow 社区不喜欢图片,但是这张图真的很棒,可能会对将来发现这个问题的人有所帮助:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-04-18
            • 1970-01-01
            • 1970-01-01
            • 2020-11-22
            • 1970-01-01
            • 1970-01-01
            • 2018-05-17
            相关资源
            最近更新 更多