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

7
这是我第一次接触Rust,我正在阅读当前版本的Rust Book中关于向量的章节。我之前有使用其他语言的经验(主要是函数式语言,在那些语言中下面提到的问题被隐藏了)。
运行以下代码片段(来自书中),将返回3
fn main() {
  let v = vec![1, 2, 3, 4, 5];
  let third: &i32 = &v[2];
  println!("{}", third);
}
  1. 我不明白的第一件事是为什么println!宏内部的third没有被引用。我本来期望上面的代码会打印v的第三个元素的内存地址(就像在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

以上所有问题都是自动解引用(auto-dereferencing)的表现吗?之前的章节只是简单提及了一下它。如果是这样的话,那么这本书需要重写,因为这种描述比解释更加困惑。


1
如果你想知道类型,可以将 () 指定为类型并查看错误消息,例如 let third: () = v[2]; - starblue
可能重复 https://dev59.com/kV4c5IYBdhLWcg3wgqc8? - fghj
1个回答

2

免责声明:我也在学习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)],
            },
            ...
        ));
    };
}

对于第二个案例,这意味着对于{}格式化程序,特质Displayfmt函数将分别针对third*third的引用进行调用。
让我们应用这个逻辑到:
- 第二种情况: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,即适用于=的复制语义,而不是默认的移动语义)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接