【问题标题】:How to push additional element to Vec<&Vec<String>>?如何将附加元素推送到 Vec<&Vec<String>>?
【发布时间】:2022-08-09 12:44:15
【问题描述】:

我正在尝试完成一些相当简单的事情,但不确定如何在 Rust 中完成。

我有一个 Vec<&Vec>,类似于下面的示例。

[
 [\"a1\", \"b2\", \"c3\"],
 [\"d1\", \"e2\", \"f3\"],
 [\"g1\", \"h2\", \"i3\"]
]

我想在每个向量的末尾添加一个额外的字符串。

[
 [\"a1\", \"b2\", \"c3\", \"something\"],
 [\"d1\", \"e2\", \"f3\", \"something\"],
 [\"g1\", \"h2\", \"i3\", \"something\"]
]

到目前为止我尝试过的内容如下:

vec_of_strings
    .iter_mut()
    .map(|x| x.clone().push(\"something\".to_string()))
    .collect::<Vec<_>>();

println!(\"{:?}\", vec_of_strings);

但是输出显示没有附加任何内容。

    标签: rust push vec


    【解决方案1】:

    您所做的会创建一个新的Vec,它不会修改现有的。事实上,现有的不能被修改,因为你正在不可变地借用它们(Vec&lt;&amp;Vec&lt;_&gt;&gt; 中的&amp;)。

    请注意,使用 .iter_mut() 而不是 .iter() 在这里毫无意义,因为您没有改变元素。

    此外,Vec::push() 不会返回任何内容,因此 .to_string() 调用应该会给您一个编译时错误。 (我假设您打算在字符串文字上调用它。)

    修复上述问题:

    let new_vec_of_strings = vec_of_strings
      .iter()
      .map(|x| {
        let mut x = x.clone();
        x.push("something".to_string());
        x
      })
      .collect::<Vec<_>>();
    
    println!("{:?}", new_vec_of_strings);
    

    然而,这一切似乎都是XY problem——可能有更好的方法来实现你的目标。

    【讨论】:

    • 非常感谢你的答复。这正好解决了我的问题。仍在学习并习惯 Rust,正如您所建议的,可能有更好的方法来做到这一点,完全同意这一点。我试图解决这个问题的方式感觉很奇怪。再次感谢。
    • 还有一个额外的),所以我认为这只是一个错字并修复了它。
    【解决方案2】:

    如果我理解正确,您需要在map 中返回一个vec

    fn main() {
        let mut vec_of_strings = vec![
            vec!["a1", "b2", "c3"], 
            vec!["d1", "e2", "f3"], 
            vec!["g1", "h2", "i3"]
        ];
        println!("{:?}", vec_of_strings);
        
        let vec_of_strings: Vec<Vec<&str>> = vec_of_strings.iter_mut().map(|x| {x.push("something"); x.clone()}).collect();
        println!("{:?}", vec_of_strings);
    }
    

    Rust Playground

    【讨论】:

      【解决方案3】:

      我认为对 map 方法的用途存在误解。这种方法一般用于原始值不变的数据转换。你在这里真正做的是造成副作用,map 方法在这里根本没有帮助你。

      只需使用for 循环。这不像您通过使用 map 和 interators 来保存击键。

      但是,您提到您有一个Vec&lt;&amp;Vec&gt;。拥有这种类型似乎不适合您的目的。克隆整个 vec 只是为了添加 1 个元素对性能来说很糟糕。

      我看到了 2 个选择:要么完全拥有它,即 Vec&lt;Vec&gt;,要么只是让内部 Vecs 可变,如 Vec&lt;&amp;mut Vec&gt;

      这是第一个选项,我认为这是最惯用的:

      fn main() {
          let mut vec_of_strings = vec![
              vec!["a1", "b2", "c3"], 
              vec!["d1", "e2", "f3"], 
              vec!["g1", "h2", "i3"]
          ];
       
          for vec in vec_of_strings.iter_mut() {
              vec.push("something");
          }
          
          println!("{vec_of_strings:?}");
      }
      

      如果不接受以拥有的形式拥有它,那么另一种选择是使用Vec&lt;&amp;mut Vec&gt;

      fn main() {
          fn main() {
          let mut vec_of_strings = vec![
              vec!["a1", "b2", "c3"], 
              vec!["d1", "e2", "f3"], 
              vec!["g1", "h2", "i3"]
          ];
          
          //suppose somehow a function gave you this:
          let vec_of_mut_strings: Vec<&mut Vec<_>> = vec_of_strings
              .iter_mut()
              .collect();
          
          for vec in vec_of_mut_strings {
              vec.push("something");
          }
          
          //notice that the original vec_of_strings change
          println!("{vec_of_strings:?}");
      }
      }
      

      【讨论】:

      • “这种方法一般用于原始值不变的数据转换。”这在 Rust 中并不完全正确。在集合上调用.into_iter() 以使用它、更改元素(因为它们是拥有的)并将它们收集到不同类型的集合中的能力非常强大。
      【解决方案4】:

      一种保持原始格式的解决方案,将每个数组扩展一个条目:

      vec_of_strings
          .iter_mut()
          .map(|a| {
              let mut v = a.to_vec();
              v.push("something");
              let arr: [&str; 4] = v.try_into().unwrap();
              arr
          })
          .collect::<Vec<[&str; 4]>>();
      

      Playground

      【讨论】:

        【解决方案5】:

        我假设您的输出如下所示:

        [(), (), ()]
        

        以下是一些建议:

        • 更喜欢使用 for_each 而不是 map 进行突变:

          vec_of_strings
              .iter_mut()
              .for_each(|x| {
                  x.push("something");
              });
          
          println!("{:?}", vec_of_strings);
          

          请注意,这假设 vec_of_strings 的定义类似:

          let mut vec1 = vec!["a1", "b2", "c3"];
          let mut vec2 = vec!["d1", "e2", "f3"];
          let mut vec3 = vec!["g1", "h2", "i3"];
          let mut vec_of_strings: Vec<&mut Vec<&str>> = vec![&mut vec1, &mut vec2, &mut vec3];
          

          Playground

        • 在您的示例中,.map 中的函数不返回任何内容,因为 Vec::push 不返回向量。

          x 分隔到另一行以返回向量。

          vec_of_strings.iter_mut()
              .map(|x| {
                  x.push("something");
                  x
              })
              .collect::<Vec<&str>>();
          

          请注意,这假设 vec_of_strings 的定义类似:

          let mut vec1 = vec!["a1", "b2", "c3"];
          let mut vec2 = vec!["d1", "e2", "f3"];
          let mut vec3 = vec!["g1", "h2", "i3"];
          let mut vec_of_strings: Vec<&mut Vec<&str>> = vec![&mut vec1, &mut vec2, &mut vec3];
          

          Playground

        • 在使用 map 时,您可能还希望更明确地使用向量元素的类型 (&amp;str):

              .collect::<Vec<&str>>();
          

          代替

              .collect::<Vec<_>>();
          

          由于Vec::pushmap 中的返回类型(因此输出),编译器将其推断为Vec&lt;()&gt;

        【讨论】:

          猜你喜欢
          • 2021-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-30
          • 2020-10-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多