1

I have written a function to map over vectors. The method definition expects 3 generic parameters and defines over a input vector and function:

pub fn map<F, A, B>(mapFn: F, vect: &[A]) -> &[B]
where
    F: Fn(A) -> B,
{
    let mut list = vec![];

    for v in vect {
        let mut value = mapFn(v);
        list.push(value);
    }

    &list[..]
}

I get this error:

error[E0308]: mismatched types
 --> src/main.rs:8:31
  |
8 |         let mut value = mapFn(v); // <------ This is where I get the error
  |                               ^ expected type parameter, found &A
  |
  = note: expected type `A`
             found type `&A`

I also checked Generics Error: expected type parameter, found struct, but it did not seem to be about the same problem.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Aditya Singh
  • 15,810
  • 15
  • 45
  • 67

2 Answers2

3

There are a few issues with your code. Rust's ownership model is tough but fair...


The main one (not directly causing your error) is this:

let mut list = vec![]; // allocate in a function
// [cut] 
&list[..] // return a reference to memory allocated in the function
          // ... which gets freed at the end of the function
          // (if this compiled you'd have a dangling reference)

Fix Return the Vec directly


Second one (this one directly addresses your error): you're trying to take elements out of a slice (vect), put them into a new vector (list) and return the new vector. A slice like vect does not own its elements, so all it can give you are references, but list is a Vec, so it wants to own its elements.

Fix In order to have an owned version of the original elements, you have to either:

  1. Have vect contain items that you can Clone (so you can store a copy of them in the new vector). This restricts the genericity of your function (not all types are Clone-able). You can achieve it by adding a A: Clone bound to your function's signature and calling mapFn(v.clone())
  2. Give the function full ownership of the data to begin with, i.e. make the input parameter a vect: Vec<A>. The drawback of this is that when you move the elements from vect to list, vect is no longer usable.

playground


Note that the Rust standard library defines map on iterators, which is a more flexible approach. It applies the function in place, element by element while iterating the input, so it does not require to own or clone the elements.

Paolo Falabella
  • 24,914
  • 3
  • 72
  • 86
1

First of all, there is a map adaptor for iterators.

Your problem here is that mapFn expect a owned value, but iterate over a slice (&[A]) gives you refs.

You can take a Vec as parameter or make fnMap accept &A to solve your problem.

Finally, returning a ref is not what you want here, you can just return the plain Vec.

Grégory OBANOS
  • 973
  • 8
  • 13