Adapt Vec<&T> to &[T] preferably without Clone or Copy

Problem Statement

I am trying to call fn some_api_function() which takes &[T] as parameter. To generate that parameter for the function, I tried to call flat_map on a Vec of Vecs (which itself buried inside RefCell). But I have trouble convert Vec<&T> to &[T]. I'd preferably avoid Copy or Clone the entire dataset for performance reason, as some_api just need to read-only borrow the data.

Code to illustrate:

use std::cell::RefCell;
pub struct EnvVar {}

pub struct Arena {
    services: RefCell<Vec<Service>>,
}

pub struct Service {
    env_vars: Vec<EnvVar>,
}

pub fn some_api(env_vars: &[EnvVar]) {}

fn main() {
    let arena = Arena {
        services: RefCell::new(vec![Service {
            env_vars: vec![EnvVar {}],
        }]),
    };
    let env_vars: Vec<&EnvVar> = arena
        .services
        .borrow()
        .iter()
        .flat_map(|compose_service| compose_service.env_vars.as_ref())
        .collect();

    some_api(&env_vars);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:27:14
   |
27 |     some_api(&env_vars);
   |              ^^^^^^^^^ expected slice, found struct `Vec`
   |
   = note: expected reference `&[EnvVar]`
              found reference `&Vec<&EnvVar>`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

You can't convert a Vec<&T> to a Vec<T> (from which you can get an &[T] without cloning (or copying for Copy types).
You have to add a cloned() call to the line creating env_vars.

-let env_vars: Vec<&EnvVar> = arena
+let env_vars: Vec<EnvVar> = arena
        .services
        .borrow()
        .iter()
        .flat_map(|compose_service| compose_service.env_vars.as_ref())
+        .cloned()
        .collect();

    some_api(&env_vars);

Thank you @RedDocMD. I'd like to avoid Copy or Clone the entire dataset for performance reason, as the Vec of Vecs can grow quite big and some_api just need to read-only borrow the data.

In that case, you'd need to store your data in a different way such that all the env_vars are present in a single vector from the get-go.
One way would be move all the env_vars into the Arena and store indices in the child structs.

1 Like

Is it an option to use &[&EnvVar] in your function perhaps? You can get such a slice from Vec<&EnvVar> without cloning.

2 Likes

Thanks @RedDocMD and @jbe I can certainly modified some_api function to take &[&EnvVar], it just feels a bit weird as a newbie person to Rust.

You'll get used to it, don't worry.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.