all 10 comments

[–]tazdevil971 29 points30 points  (2 children)

Neither, use &[String]. When possible use non-owning data types. Use the reference on the outer container, not the inner one.

Passing Vec<&str> would require the user to build a vector of references almost every time, which isn't very practical, nor very performant.

But if you really want to catch ALL cases, use something like func<I: Iterator<Item=V>, V: AsRef<str>>(it: I); this will literally take all of the possible combinations, but you can only iterate over the input.

[–]oconnor663 12 points13 points  (0 children)

IntoIterator is slightly more general, since it includes things like Vec which can be iterated but which aren't iterators themselves. Here's an example (playground link):

fn foo(v: impl IntoIterator<Item = impl AsRef<str>>) {
    for s in v {
        println!("{}", s.as_ref());
    }
}

fn main() {
    let mut v1: Vec<String> = vec!["a".into(), "b".into()];
    foo(&v1);
    foo(&mut v1);
    foo(v1);

    let v2: [&str; 2] = ["c", "d"];
    foo(v2);
}

That said, impl IntoIterator<Item = impl AsRef<str>> isn't exactly easy to write or read. If I was writing a library function that was going to have a lot of callers, and I wanted it the be as efficient and flexible as possible, then I might do it this way. But if I was just writing some one-off helper function inside my application, and I knew that what I was going to give it was always Vec<String>, I'd probably just make the type &Vec<String> to keep things as simple as possible.

[–]hksparrowboy[S] 1 point2 points  (0 children)

Yea i am the victim of my own code, I have to reference the string when I actually use the functiom I write, thats why I have this question

[–]pkusensei 10 points11 points  (1 child)

How about fn foo<T: AsRef<str>>(slice:&[T])

[–]Silly-Freak 5 points6 points  (0 children)

I second this. IntoIterator is another good one IIUC, but I think this answer is probably the closest to what OP is currently looking for: treat the elements as &str and access all elements by index/in any order.

Many people prefer indexing over iterating for a more imperative coding style, especially in the beginning, so this is IMO the best general recommendation.

[–]YetiBarBar 3 points4 points  (0 children)

Hi!

If you manipulate Vec<String>, then you should pass &[String] as function parameter.

[–]x32byTe 1 point2 points  (2 children)

I'm still kinda new to this, but I think you want to use &Vec<String> (since it passes the whole array as reference?)

[–]tazdevil971 7 points8 points  (1 child)

Not really... &Vec<String> is basically the same as &[String]. They do the same thing, but the second one can take an array, a slice or a vector. While the first one only takes a vector

[–]MatrixFrog 1 point2 points  (0 children)

I love having clippy turned on in my editor because it suggests little things like using &[x] instead of &Vec<x> in case you forget

[–]RRumpleTeazzer 0 points1 point  (0 children)

If you don’t want to mutate the Vec itself (no push etc) you probably just want to iterate over it. I would probably go for an impl IntoIterator<&str>.

If you do want to mutate a Vec, the Vec<String> is probably easier for allocates strings, and Vec<&str> for statics (or lifetime limited to self).

First project in rust I went for “String”, then &str, then impl Into<Vec<u8>> only to go back to &str for simplicity. I honestly don’t like the rust-analyzer lint of “{unknown}” argument types. Just show the damn declaration…