- Rust By Example* 说
赋值左侧的ref
借用等效于右侧的&
借用。
现在:
let u = 42u32;
let x = &u;
println!("{:p}",x);
let ref y = u;
println!("{:p}", y);
// same addr printed and that's expected
let v = [1, 2, 3];
for i in &v {
println!("{:p}", i);
// 0x7fff4ae23334
// 0x7fff4ae23338
// 0x7fff4ae2333c
// ok, still expected
}
for ref j in v {
println!("{:p}",j);
// SAME addr (and not 0x7fff4ae23334) printed for each round, WHY?
}
字符串
我想知道for ref j in v
循环中的j
到底是什么。
2条答案
按热度按时间fwzugrvs1#
确实,
let ref foo = bar;
等价于let foo = &bar;
。但是在for循环中有一个不同的机制。一般而言字符串
使用IntoIterator特征将
bar
“转换”为迭代器。所以当你写型
rust将使用实现Vec IntoIterator,这将产生
T
s。但是如果你写型
rust将对&Vec使用实现实现IntoIterator,这将产生
&T
s。请注意,也有&mut Vec的实作。for foo in bar
中foo
将绑定到迭代器返回值这是因为for
循环是一种语法糖,它将这种语法糖分解为以下内容(请参阅文档):型
再回到我们的例子。
for foo in &v
将foo
绑定到对向量元素的引用。这就是为什么它们都有自己的连续地址(注意,每次迭代增加4个字节,大小为i32
)。但是,当我们说for ref foo in bar
ref foo
将绑定到堆栈分配变量时,迭代器返回的值将在每次迭代中移动到该变量中(参见上面的next
)。由于在每次迭代中使用相同的堆栈变量,因此它们都将具有相同的地址,但每次都会更改值。z9smfwbn2#
我想你对
ref
的理解已经足够好了。然而,有一些神奇的事情发生了,允许你引用一个临时变量。例如,看看这段代码。
字符串
ref a
是一个扩展模式。这意味着字符串存储在一个临时的、未命名的绑定中,该绑定将在此范围结束时被删除。你可以这样想象:型
这解释了为什么
j
总是相同的地址。请注意,for _ in v
消耗v
并迭代所拥有的值。无论in
之前的模式如何,都会发生这种情况。换句话说,let a = &b
与let ref a = b
相同,但for a in &b
与for ref a in b
不同。你可以重写for循环,看起来像这样:型
被打印的地址是
temp
的地址,它在每次迭代中存储一个拥有的值。创建j
时,该值既不在v
中,也不在v_iter
中。