Ali
Ali

Reputation: 33

Rust: apply the function to each element of vector

Given the following function:

fn some_function<K, F: Fn(K) -> K>(f: F, vs: Vec<K>) -> Vec<K> {
    let mut index = 0;
    let new_vec = vs.iter().map(|x| {
        index += 1;
        for _ in 1 .. index {
            x = f(x); // <- error here: mismatched types expected reference `&K` found type parameter `K`
        }
        *x
    }).collect();
    new_vec
}

How can i make it work ?

Upvotes: 0

Views: 846

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 299820

There are 3 types of variables in Rust:

  • Values.
  • Shared References.
  • Mutable References.

In turn, this maps to 3 different iteration functions:

  • .into_iter() will return an iterator over values.
  • .iter() will return an iterator over shared references.
  • .iter_mut() will return an iterator over mutable references.

You simply didn't pick the right function, and should have used into_iter instead.

fn some_function<K, F: Fn(K) -> K>(f: F, vs: Vec<K>) -> Vec<K> {
    vs
        .into_iter()
        .enumerate()
        .map(|(index, mut x)| {
            for _ in 0..index {
                x = f(x);
            }
            x
        }).collect()
}

Additionally:

  • enumerate will allow you to get an index of each element as you iterate, so that you do not have to maintain the index yourself.
  • To iterate i items, you want 0..i, not 1..i.

For performance, however, it would be better to in-place modify the elements if possible. This allows reusing buffers, including the vector's own buffer. The result would be:

fn some_function<K, F: Fn(&mut K)>(f: F, vs: &mut Vec<K>) {
    vs
        .iter_mut()
        .enumerate()
        .for_each(|(index, x)| {
            for _ in 0..index {
                f(x);
            }
        });
}

Upvotes: 2

jthulhu
jthulhu

Reputation: 8678

This example doesn't work because .iter() will not produce an iterator of owned variables, but references to elements of vs. You could patch your code by turning it into into_iter():

fn some_function<K>(f: impl Fn(K) -> K, vs: Vec<K>) -> Vec<K> {
    let mut index = 0;
    vs.into_iter()
    .map(|mut x| {
        index += 1;
        for _ in 1..index { x = f(x); }
        x
    })
    .collect()
}

But you don't need to keep track of index:

fn some_function<K>(f: impl Fn(K) -> K, vs: Vec<K>) -> Vec<K> {
    vs
    .into_iter()
    .enumerate()
    .map(|(i, mut x)| {
        for _ in 0..i { x = f(x); }
        x
    })
   .collect()
}

Upvotes: 1

Related Questions