在Rust中创建一个向量的向量

13

这段代码不能编译:

fn main() {
    let m1 = vec![1, 2, 3];
    let m2 = vec![&m1, &m1, &m1];
    let m3 = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];

    for i in &m2 {
        for j in i {
            println!("{}", j);
        }
    }

    for i in &m3 {
        for j in i {
            println!("{}", j);
        }
    }
}
error[E0277]: the trait bound `&&std::vec::Vec<{integer}>: std::iter::Iterator` is not satisfied
 --> src/main.rs:8:18
  |
8 |         for j in i {
  |                  ^ `&&std::vec::Vec<{integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
  |
  = help: the trait `std::iter::Iterator` is not implemented for `&&std::vec::Vec<{integer}>`
  = note: required by `std::iter::IntoIterator::into_iter`
  1. m2m3有何不同,以至于m3不会出现问题,而m2却导致编译失败?

  2. 是否有更简单的方法来创建一个任意深度的向量嵌套(例如vector of vector of...)?我当前使用的方式(m3)似乎很笨重。


请参阅 https://dev59.com/hILba4cB1Zd3GeqPbTby 或 https://dev59.com/VWcs5IYBdhLWcg3wJQi7。 - Shepmaster
2个回答

11
“m2”和“m3”的区别在哪里?请逐步检查类型。 “m1”的类型是“Vec ”(它也可以是任何其他整数类型,但现在我假设它是“isize”)。为什么?因为“vec![]”宏中的元素是“isize”类型。现在您正在创建“m2”:
let m2 = vec![&m1, &m1, &m1];

这个宏中元素的类型是什么?我们已经说过m1的类型是Vec<isize>,因此&m1的类型是&Vec<isize>。所以m2的结果类型是Vec<&Vec<isize>>(一个由其他向量引用组成的向量)。
然而,m3的类型是Vec<Vec<isize>>,因为(外部的)vec![]宏中的元素的类型是Vec<isize>(没有引用!)。
提示:要轻松检查任何变量(如foo)的类型,请访问此处
let _: () = foo;

这将导致编译器错误,告诉您foo的类型。

...以便m3不会出现问题,但m2会阻止编译吗?

现在我们知道了m2m3的类型,让我们看看循环。 for循环通过接受实现IntoIterator的内容来工作。您正在传递&m2,它的类型为&Vec<&Vec<isize>>(请注意两个引用)。我们可以看到,确实为向量引用实现了IntoIterator

impl<T> IntoIterator for &Vec<T> {
    type Item = &T
    // ...
}

这意味着你会得到一个迭代器,它会输出内部类型T(type Item = &T)的引用。我们的内部类型m2是&Vec<isize>,因此我们将获得类型为&&Vec<isize>(两个引用!)的项。变量i具有这个精确的类型。
然后,您想再次使用此内部循环进行迭代:
for j in i { ... }

但是i有双重引用类型,并且没有针对该类型的IntoIterator实现。要迭代它,您必须像这样取消引用:

for j in *i { ... }

甚至更好的是,在外部循环中使用模式匹配来剥离的类型,使其成为&Vec<isize>类型(只有一个参考!):
for &i in &m2 { ... }

您的m3循环执行相同的操作,但由于m3是另一种类型(引用少一),它可以正常工作(希望您能看出原因)。


有没有更简单的方法创建一个向量的向量,以达到任何所需的深度?

即使m2起作用,它也不会保存与m3相同的值。要将m2设置为Vec<Vec<isize>>类型(如m3),您应该使用clone而不是对其进行引用。

let m2 = vec![m1.clone(), m1.clone(), m1.clone()];

我们可以通过使用宏的vec![_; _]形式来进一步改进:
let m2 = vec![m1; 3];   // three times the value of `m1`

作为最后的记号,你应该考虑不要使用嵌套的Vec。由于值分散在整个内存中而不是集中在一个地方,所以嵌套会产生额外的开销。

一些事情...1)感谢您的帮助!我很感激您快速而详尽的回复。 2)如果三个m1之间存在混淆,我很抱歉。我实际上并不打算这样做,但我不想创建额外的变量并为示例添加额外的噪音。 3)我之所以选择嵌套向量,是因为我在网上找到的作业任务(<-必须喜欢好的廉价练习问题)要求这样做。再次感谢 - Ian Fleming

0
添加 iter 函数到第二个 for
fn main() {
let m1 = vec![1, 2, 3];
let m2 = vec![&m1, &m1, &m1];
let m3 = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];

for i in &m2 {
    for j in i.iter() {
        println!("{}", j);
    }
}

for i in &m3 {
    for j in i {
        println!("{}", j);
    }
}

}


你好!欢迎来到SO。 虽然这可能解决问题,你能否也提供一个简短的解释为什么这是一个解决方案? - undefined

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