This fundamentally can't work, because the layouts aren't compatible.
To get a &[&str], a [&str] has to exist somewhere so the reference can point to it, but there isn't one. You only have a [Foo]. (Note that a [String] doesn't work either, because String and &str have different layouts.)
/// Converts `Vec<Foo>` into a new `Vec<String>`.
/// Consumes `Vec<Foo>`, so the `String`s are moved, not reallocated.
fn vec_of_foo_into_vec_of_string(vec: Vec<Foo>) -> Vec<String> {
vec.into_iter().map(|x| x.bar).collect()
}
/// Converts `&[Foo]` into a new `Vec<&str>`.
/// The `[Foo]` slice (which could be in a `Vec`) is left intact.
/// The returned `&str`s cannot live for longer than the input slice,
/// since they refer to the `String`s in the `Foo`s.
fn slice_of_foo_to_vec_of_str(slice: &[Foo]) -> Vec<&str> {
slice.iter().map(|x| x.bar.as_ref()).collect()
}
In addition to the limitations you encountered with the orphan rule ("not defined in the current crate"), it is generally a good idea to be careful not to overuse the From/Into traits. The doc has guidelines for using these traits: https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from
Depending on how the resulting slices are used, it may be workable to return the iterators directly, without collect. For cases where you only visit them sequentially, you use the iterator. For cases where you need random access, or visiting multiple times then you call your helper function then collect to a Vec.