Reputation: 424
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.
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);
}
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
Upvotes: 1
Views: 309
Reputation: 361565
It's not possible, and here's why:
Imagine that each T
takes up 500 bytes. Meanwhile each &T
, being a 64-bit address, takes only 8 bytes. What you get is:
A &[T]
is a reference to a slice of contiguous T
s, each 500 bytes. If the slice had 20 T
s that contiguous block of memory would be 20 × 500 bytes = 10 KB large.
A Vec<&T>
containing 20 elements would have a bunch of addresses side-by-side and would only need a block of 20 × 8 bytes = 160 bytes.
There is no cheap way to turn a 160-byte block of &T
s into a 10 KB block of T
s. Their memory layouts are not compatible. Your only options are:
Vec<T>
instead of Vec<&T>
.&[&T]
.Upvotes: 6