Vec<String> to &[&str]


#1

I think I am just failing to think correctly and failing to use google well, but…

The run method of a gtk::Application instance requires a &[&str] which is assumed to be the command line.

The std::env::args is an iterable but applying collect gives a Vec<String>. There appears to be no trivially easy way of creating a &[&str] from Vec<String> and yet this is exactly what appears to be assumed is available.


#2

You can do:

let v = std::env::args().collect::<Vec<_>>();
let v: Vec<&str> = v.iter().map(|x| &**x).collect();
app::run(&v);

#3

It’s unfortunate but as far as I’m aware @vitalyd 's suggestion is the only way.


#4

You can fix method of gtk::Application to something like fn f<T: AsRef<str>>(arr: &[T]), and send PR to gtk-rs.


#5

I am not sure that is feasible since the gtk-rs API is auto generated from the GIR files provided by the GTK+ folk.

@vitalyd came up with a couple of lines that fix my problem that I might have got to eventually, but it would have taken a long time. I am now massively further forward and can progress. So thanks to @vitalyd for moving me on.


#6

I found that:

let v: Vec<&str> = v.iter().map(|x| x.as_ref()).collect();

also works and may be more self-documenting, at least for some.


#7

Yup. A couple more options along these lines for your choosing:

let v: Vec<&str> = v.iter().map(String::as_ref).collect();

or

let v: Vec<&str> = v.iter().map(<_>::as_ref).collect();

#8

I like the first of these, the second seems a little hieroglyphic, but I guess this is now getting down to personal taste. Obviously to really talk about performance, one must benchmark, but a priori as hypotheses are any of these the most likely to be more efficient?


#9

Yeah, the form one would pick is mostly down to familiarity/comfort with Rust. I’d expect no performance difference between the variants here.

Also, the 2nd one may seem obtuse, but if anyone has used collect on an iterator they probably have seen (at some point) something like ...collect::<Vec<_>>(). If so, <_>::as_ref() shouldn’t be too foreign.


#10

I’ve always used this one:

let v: Vec<&str> = v.iter().map(AsRef::as_ref).collect();

#11

Are we code-golfing here? :slight_smile: That one is one char shorter:

let v: Vec<_> = v.iter().map(|s|s.as_str()).collect();

#12

This is a limitation of the API provided; there’s no zero-cost way to create a &[&str] from Vec<String>, since the elements have different sizes. &str and String do not share the same memory layout. This is the same situation as with Vec<Vec<u8>> not being castable to &[&[u8]]. All of the suggestions provided in this thread are valid approaches, but ideally the API provided by GTK-rs(?) would change. Filing an issue may be a good idea.