2015-05-04 119 views
25

尽管矢量最适合用于程序编程,但我想对它们使用map函数。以下片段的工作原理如下:使用带有矢量图的地图

fn map<A, B>(u: &Vec<A>, f: &Fn(&A) -> B) -> Vec<B> { 
    let mut res: Vec<B> = Vec::with_capacity(u.len()); 
    for x in u.iter() { 
     res.push(f(x)); 
    } 
    res 
} 

fn f(x: &i32) -> i32 { 
    *x + 1 
} 

fn main() { 
    let u = vec![1, 2, 3]; 
    let v = map(&u, &f); 
    println!("{} {} {}", v[0], v[1], v[2]); 
} 

为什么标准库中没有这样的函数? (也在std::collections::LinkedList)。是否有另一种方式来处理它?

回答

41

铁锈喜欢比它更普遍;映射是通过迭代器完成的,而不是单独的向量或片。

一对夫妇示威:

let u = vec![1, 2, 3]; 
let v: Vec<_> = u.iter().map(f).collect(); 
let u = vec![1, 2, 3]; 
let v = u.iter().map(|&x| x + 1).collect::<Vec<_>>(); 

.collect()大概是它最神奇的部分,让你的迭代器的所有元素收集到了大量各种不同类型的,如图所示由implementors of FromIterator。例如,T的迭代器可被收集到Vec<T>,其中char可被收集到String(K, V)对到HashMap<K, V>等等。

这种使用迭代器的方式也意味着您甚至不需要创建其他语言或其他技术的中间向量;这是更高效的,并且通常是自然的。

9

正如指出的by bluss,您还可以使用可变迭代变异到位的价值,而不改变类型:

let mut nums = nums; 
for num in &mut nums { *num += 1 } 
println!("{:p} - {:?}", &nums, nums); 

功能Vec::map_in_place在拉斯特1.3过时,不再存在于Rust 1.4中。

克里斯摩根的答案是最好的解决方案99%的时间。但是,有一个称为Vec::map_in_place的专用功能。这具有不需要任何附加的存储器分配的益处,但它要求的输入和输出类型是相同的大小(thanks Levans),并且是目前不稳定:

fn map_in_place<U, F>(self, f: F) -> Vec<U> 
    where F: FnMut(T) -> U 

一个例子:

#![feature(collections)] 

fn main() { 
    let nums = vec![1,2,3]; 
    println!("{:p} - {:?}", &nums, nums); 

    let nums = nums.map_in_place(|v| v + 1); 
    println!("{:p} - {:?}", &nums, nums); 
} 
+3

如果你不需要map_in_place的神奇的类型改变,你可以使用可变的迭代器。 'for elt in&mut v {* elt = * elt + 1; }' – bluss

+2

请注意,它也需要输入和输出类型具有相同的大小,当然并非总是如此。 – Levans

+1

注意'map_in_place'从1.3开始已被弃用。我想我们现在使用'.into_iter()。map(...).collect()'? – kennytm