这是我第一次与Rust接触,我正在阅读Rust Book当前版本中有关向量的章节。我确实有使用其他语言的经验(主要是功能性语言,其中隐藏了以下问题)。
运行以下代码段(来自本书)将返回3
:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("{}", third);
}
third
宏内的println!
。我希望上面的代码显示v
的第3个元素的内存地址(如C和C ++),而不是其内容。现在考虑代码(注意这次在println!
中引用):
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("{}", *third);
}
*
没有区别?最后,让我们重写上面的代码片段,以完全消除引用:
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: i32 = v[2];
println!("{}", third);
}
v[2]
真正具有什么类型:是&i32
还是i32
?以上所有都是自动取消引用的体现吗?在上一章中只提到过一次吗? (如果是这样,则应该重写这本书,因为它比澄清起来更令人困惑。)
答案 0 :(得分:0)
免责声明:我也在学习Rust,所以请带一点盐。
要了解会发生什么,使用cargo-expand可能会更容易。
对于代码
fn main() {
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("{}", third);
}
我们得到了(我已经删除了不相关的代码)
fn main() {
...
let third: ...
{
::io::_print(::std::fmt::Arguments::new_v1_formatted(
...
&match (&third,) {
(arg0,) => [::std::fmt::ArgumentV1::new(arg0, ::std::fmt::Display::fmt)],
},
...
));
};
}
第一种/最后一种情况,
fn main() {
...
let third: ...
{
::io::_print(::std::fmt::Arguments::new_v1_formatted(
...
&match (&*third,) {
(arg0,) => [::std::fmt::ArgumentV1::new(arg0, ::std::fmt::Display::fmt)],
},
...
));
};
}
第二种情况。
粗略地讲,这意味着对于{}
格式化程序,将调用功能fmt
(具有特征Display
的功能)third
以引用*third
或{{ 1}}。
让我们将此逻辑应用于
第二种情况:third: &i32
然后是*third: i32
,这是impl Display for i32
适用的地方。
第一种情况:third: &i32
,这也因为impl<'_, T> Display for &'_ T
(其中T
是i32
)而起作用
最后一种情况:third: i32
:与第一种情况相同。此外,v[2]
(类型为i32
)之所以有效,是因为impl Index for Vec(请注意:let third = v[2]
之所以有效是因为impl Copy for i32,即{{ 1}},而不是默认的移动语义。