不了解如何在Rust中访问向量的元素

时间:2018-12-08 20:24:45

标签: pointers vector reference rust

这是我第一次与Rust接触,我正在阅读Rust Book当前版本中有关向量的章节。我确实有使用其他语言的经验(主要是功能性语言,其中隐藏了以下问题)。

运行以下代码段(来自本书)将返回3

fn main() {
  let v = vec![1, 2, 3, 4, 5];
  let third: &i32 = &v[2];
  println!("{}", third);
}
  1. 我不明白的第一件事是为什么未引用third宏内的println!。我希望上面的代码显示v的第3个元素的内存地址(如C和C ++),而不是其内容。

现在考虑代码(注意这次在println!中引用):

fn main() {
  let v = vec![1, 2, 3, 4, 5];
  let third: &i32 = &v[2];
  println!("{}", *third);
}
  1. 为什么上面的代码代码产生的输出与其上面的代码完全相同,好像*没有区别?

最后,让我们重写上面的代码片段,以完全消除引用:

fn main() {
  let v = vec![1, 2, 3, 4, 5];
  let third: i32 = v[2];
  println!("{}", third);
}
  1. 为什么最后一个版本产生的输出与前两个相同? v[2]真正具有什么类型:是&i32还是i32

以上所有都是自动取消引用的体现吗?在上一章中只提到过一次吗? (如果是这样,则应该重写这本书,因为它比澄清起来更令人困惑。)

1 个答案:

答案 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(其中Ti32)而起作用

  • 最后一种情况:third: i32:与第一种情况相同。此外,v[2](类型为i32)之所以有效,是因为impl Index for Vec(请注意:let third = v[2]之所以有效是因为impl Copy for i32,即{{ 1}},而不是默认的移动语义。