Quite the opposite, as a matter of fact: usage of Rc
and "alike" is very explicit in Rust.
That's, by the way, why @Aiden01 was confused: most functional languages, since they are garbage collected, use pointers "for everything", hence allowing a [T]
in return position (when actually the returned value in those case is something more like GcPtr<[T]>
).
Hence the only two solutions to do it in Rust:
-
Put the slice behind a pointer, with, for instance, just a Box
,
-
Use an enum
to be able to "inline" your two possibilities:
enum MaybeArray<T> {
NotEmpty([T; 1]),
Empty,
}
Which actually just boils down to Option<[T; 1]>
(what @farnbams suggested).
Since a fixed-size array such as [T; 1]
is not better than just a T
, people will go for a tweak of the former solution: "resizable arrays", i.e., a Vec
tor:
/// Rust's `Maybe`
enum Option<T> {
Some(T),
None,
}
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
match option {
Option::Some(value) => vec![value],
Option::None => vec![],
}
}
or, with mutation:
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
let mut vec = Vec::new(); // empty mutable vector
match option {
Option::Some(value) => {
vec.push(value);
vec
},
Option::None => vec,
}
}
at which point the "evaluate to vec
" can be factored out:
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
let mut vec = Vec::new(); // empty mutable vector
match option {
Option::Some(value) => {
vec.push(value);
},
Option::None => {},
}
vec
}
at which point extending the Vec
from an option follows the option::IntoIter
logic:
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
let mut vec = Vec::new(); // empty mutable vector
vec.extend(option);
vec
}
at which point (extending an empty collection), can be one-lined with:
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
<Vec<T> as ::std::iter::FromIterator<T>>::
from_iter(option)
}
or, in the more succint form (using type inference) (also suggested by @farnbams) :
pub
fn option_to_vec<T> (option: Option<T>) -> Vec<T>
{
option.into_iter().collect()
}
and at which point, the code can be optimized into using iterators instead of forcing the evaluation (if a caller wants a Vec
, all they have to do is call .collect()
afterwards):
pub
fn option_elements<T> (option: Option<T>) -> impl Iterator<Item = T>
{
option.into_iter()
}