Подтвердить что ты не робот

Использование карты с векторами

Хотя векторы лучше всего подходят для процедурного программирования, я хотел бы использовать для них функцию 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). Есть ли другой способ справиться с этим?

4b9b3361

Ответ 1

Rust любит быть более общим, чем это; отображение выполняется по итераторам, а не только по отдельным векторам или срезам.

Несколько демонстраций:

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(), вероятно, является самой волшебной его частью и позволяет собирать все элементы итератора в большое количество различных типов, как показано разработчиками FromIterator. Например, итератор T можно собрать до Vec<T>, из char можно собрать до String, из (K, V) пар до HashMap<K, V> и т.д.

Этот способ работы с итераторами также означает, что вам часто даже не нужно создавать промежуточные векторы, где на других языках или с другими методами вы бы хотели; это более эффективно и обычно так же естественно.

Ответ 2

Как указано bluss, вы также можете использовать изменяемый итератор для изменения значения на месте без изменения типа:

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

Функция Vec::map_in_place устарела в Rust 1.3 и больше не присутствует в Rust 1.4.

Ответ Криса Моргана - лучшее решение в 99% случаев. Однако существует специализированная функция Vec::map_in_place. Это имеет преимущество не требовать дополнительных распределений памяти, но требует, чтобы тип ввода и вывода был одного размера (благодаря 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);
}