2015-05-04 15 views
25

Mặc dù các vectơ phù hợp nhất cho lập trình thủ tục, tôi muốn sử dụng chức năng map trên chúng. Đoạn mã sau hoạt động:Sử dụng bản đồ với Vectors

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]); 
} 

Tại sao không có bất kỳ chức năng nào như vậy trong thư viện chuẩn? (và cũng trong std::collections::LinkedList). Có cách nào khác để đối phó với nó?

Trả lời

41

Rust thích tổng quát hơn thế; lập bản đồ được thực hiện trên các trình lặp, thay vì chỉ trên các vectơ hoặc các lát.

Một vài cuộc biểu tình:

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() có lẽ là một phần kỳ diệu nhất của nó, và cho phép bạn thu thập tất cả các yếu tố của iterator vào một lượng lớn các loại khác nhau, như thể hiện theo số implementors of FromIterator. Ví dụ: một trình lặp của T s có thể được thu thập tới Vec<T>, trong số char s có thể được thu thập theo số, trong số (K, V) các cặp đến HashMap<K, V>, v.v.

Cách làm việc với trình vòng lặp này cũng có nghĩa là bạn thậm chí sẽ không cần phải tạo các vectơ trung gian ở các ngôn ngữ khác hoặc với các kỹ thuật khác mà bạn muốn; điều này hiệu quả hơn và thường là tự nhiên.

9

Như đã chỉ ra by bluss, bạn cũng có thể sử dụng iterator có thể thay đổi để biến những giá trị tại chỗ, mà không thay đổi các loại:

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

Chức năng Vec::map_in_place đã bị phản đối ở Rust 1.3 và là không còn hiện diện trong Rust 1.4.

Câu trả lời của Chris Morgan là giải pháp tốt nhất 99% thời gian. Tuy nhiên, có một chức năng chuyên biệt gọi là Vec::map_in_place. Điều này có lợi ích của việc không đòi hỏi bất kỳ cấp phát bộ nhớ bổ sung, nhưng nó đòi hỏi rằng các đầu vào và đầu ra kiểu có cùng kích thước (thanks Levans) và hiện đang không ổn định:

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

Một ví dụ:

#![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

Nếu bạn không cần thay đổi kiểu phép thuật của map_in_place, bạn chỉ có thể sử dụng trình lặp có thể thay đổi được. 'cho elt in & mut v {* elt = * elt + 1; } ' – bluss

+2

Lưu ý rằng nó cũng yêu cầu các kiểu đầu vào và đầu ra có cùng kích thước, mà chắc chắn không phải luôn luôn như vậy. – Levans

+1

Lưu ý rằng 'map_in_place' đã không còn được dùng kể từ 1.3. Tôi đoán chúng ta sử dụng '.into_iter(). Map (…) .collect()' bây giờ? – kennytm

Các vấn đề liên quan