rust 如何将附加元素推送到Vec&lt;&amp;Vec< String>&gt;?

vx6bjr1n  于 2023-10-20  发布在  其他
关注(0)|答案(5)|浏览(130)

我正在尝试完成一些相当简单的事情,但不知道如何在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);

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

iezvtpos

iezvtpos1#

你正在做的是创建一个新的Vec,它不会修改现有的Vec。事实上,现有的不能修改,因为你是不可改变地借用它们(Vec<&Vec<_>>中的&)。
请注意,在这里使用.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--可能有一个更好的方法来实现您的目标。

8aqjt8rx

8aqjt8rx2#

如果我理解正确的话,你需要在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

vybvopom

vybvopom3#

我认为对map方法的用途存在误解。此方法通常用于原始值保持不变的数据转换。你在这里实际上做的是引起副作用,map方法在这里根本帮不上忙。
使用for循环。这不像你通过使用Map和交互器来节省时间。
但是,你提到你有一个Vec<&Vec>。拥有这种类型似乎不适合你的目的。克隆整个vec只是为了添加一个元素,这对性能来说是很糟糕的。
我有两个选择:或者完全拥有,即Vec<Vec>,或者只是让内部的Vec s可变,就像在Vec<&mut Vec>中一样。
这是第一个选项,我认为这是最惯用的:

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<&mut Vec>

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:?}");
}
}
x8goxv8g

x8goxv8g4#

我假设你的输出看起来像这样:

[(), (), ()]

以下是一些建议:

  • 更喜欢使用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时,您可能还希望更明确地说明向量元素(&str)的类型:
.collect::<Vec<&str>>();

而不是

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

由于map中的返回类型为Vec::push,因此编译器将其推断为Vec<()>(因此输出)。

lkaoscv7

lkaoscv75#

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

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

相关问题