Vectors
An array cannot change size, but a Vec
may. Vectors are structs that live on the heap and are growable like ArrayList
in Java. We create an empty Vec
with the new
associated function:
let mut names: Vec<&str> = Vec::new();
Since the list is empty, the compiler cannot infer the type and an explicit type is needed in the declaration. We could leave off the type if a later operation indicates the type, as this push
call does:
let mut names = Vec::new();
names.push("Meg Murry");
We can also add a generic type parameter to the new
call:
let mut names = Vec::<&str>::new();
In Java, we would have written the type as Vec<&str>
, not Vec::<&str>
. In Rust, when a generic type is referenced outside of the typename slot of a declaration, we need an extra ::
between the type name and the generic parameter. Without this extra ::
, the Rust grammar has an ambiguity. The <
could be either a less-than relational operator or the delimiter of the generic parameter. The ::<>
is affectionately called the turbofish operator because it looks like a speedy fish.
If we want to initialize the vector with certain values, we use the vec!
macro with an initialization list:
let mut names = vec!["Meg", "Charles Wallace", "Calvin"];
The Vec
type supports operations similar to ArrayList
.
Summary
Rust is a young language that incorporates good ideas from many different languages. Thanks to its static type system, the compiler is able to identify problems and generate fast machine code that asks few questions at runtime. Immutability is the default, reducing the wariness that we necessarily feel when sharing data. Conditionals and some loops are expressions, so we can write computational pipelines like we would in a functional language. The enum command provides a type algebra for declaring variants with tuple or record fields. When we don't need variants, we can use plain tuples or structs. Pattern matching is legal in parameter lists, loops, and conditionals, which means we don't need to muddy our code with field accesses. We may define behaviors for any type and call them in the receiver.method
syntax we expect from object-oriented languages. There's a rich standard library with abstractions like String
and Vec
.