我正在尝试学习Rust。我看到它可以对自己的地址(下面的y = &y
)进行引用,然而,由于某种原因,程序仍然能够找到引用最初指向的内容;
let x = 1;
let mut y = &x;
println!("{y:p} -> {y}"); // 0x7fffb13d6f6c -> 1
y = &y;
println!("{y:p} -> {y}"); // 0x7fffb13d6f6c -> 1
字符串
我所理解的是,在第二行之后,记忆看起来像下面这样;
| 地址|价值| value |
| --|--| ------------ |
| a1|一个| 1 |
| A2| a1| a1 |
如果指令y = &y
把内存变成这样;
| 地址|价值| value |
| --|--| ------------ |
| a1|一个| 1 |
| A2| A2| a2 |println!
将能够输出它在最后一行上输出的内容,那么第四行到底做了什么,它之后的内存是什么样子的呢?
1条答案
按热度按时间yhuiod9q1#
y
不指向自身。这是不可能的。y
正好指向它之前指向的位置,而赋值y = &y
什么也不做。那么,它的含义是什么?为什么要编译?
要回答这个问题,我们需要看看类型。这里有一个神秘的东西:如果
y
的类型为&i32
,那么&y
的类型为&&i32
,那么,当&y
和y
的类型完全不同时,您如何将它们赋值给它们呢?答案是deref强制。在编写
y = &y
时,编译器会尝试匹配类型。它无法将&&i32
与&i32
进行匹配,但它会尝试提供帮助,并认为:“很可能,程序员有一些引用,他想取消引用,但只是没有明确地写出来。所以我会为他这么做!“例如,这对于将&String
传递给采用&str
的函数非常有用。&String
与&str
的类型不同,但String
引用了str
,因此我们可以将其转换为&**s
,首先从&String
创建String
,然后从该String
创建str
,最后引用该String
创建&str
。因此,
y = &y
等价于y = &*y
。它只接受一个引用,然后立即取消引用,也就是说,只将y
中的值再次复制到y
中,有效地保留了它。