:timing
:sccache 1
Tips & Traps¶
Summary of Collections in Rust has a good summary on when to each which collection in Rust.
The length of an array is considered part of its type and thus has to be defined at compile time. You cannot define a dynamic sized array.
Vec
is essentially dynamic sized array.An array is copyable if its element type is copyable. This has a pitfall of implicity copy if you are not careful! For example, if you iterate an array using
into_iter
and then use the array again, a copy of the array will be made forinto_iter
which is likely NOT what you want.:::rust let arr = [1, 2, 3]; for v in arr.into_iter() { println!("{}", v); } for v in arr.into_iter() { println!("{}", v); }
You have to be very careful about arrays when you work with them.
Arrays of sizes from 0 to 32 (inclusive) implement the Default trait if the element type allows it. As a stopgap, trait implementations are statically generated up to size 32. This will be improved once const generics is leveraged to implement arrays.
The function from_fn provides an easy way to construct multi-elements arrays. The Rust crate array-macro provides a macro
array!
to easily construct multi-elements arrays.
Array vs Vec in Rust¶
Array is fixed size and allocated on a stack while Vec has a dynamic size and is allocated on the heap. Array is slightly faster than Vec (since stack is faster than heap) especially when the size of the sequence is small. Multi-dimensional array is even faster than Vec of Vec due to improved caching.
An array can't be empty at any time. When you crate an array, you immediately have to initialize it. In practice, you might have to initialize it twice, once with a zero/default value, and second time with some computed one.
A Vec is not copyable even if its element type is copyable, so you won't worry about copying a Vec accidentally. However, an array is copyable if its element type is copyable! This means that array has a pitfall of implicity copy if you are not careful! For example, if you iterate an array using
into_iter
and then use the array again, a copy of the array will be made forinto_iter
which is likely NOT what you want.:::rust let arr = [1, 2, 3]; for v in arr.into_iter() { println!("{}", v); } for v in arr.into_iter() { println!("{}", v); }
You have to be very careful about arrays when you work with them.
:sccache 1
use std::vec::Vec;
let arr = [1, 2, 3];
for v in arr {
println!("{}", v);
}
for v in arr {
println!("{}", v);
}
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
Construct Arrays¶
struct Foo;
let arr: [Option<Foo>; 100] = Default::default();
(Integer) Array of Zeros¶
let arr: [i32; 5] = [0; 5];
arr
let arr2 = &[0; 5];
arr2
print_type_of(arr2)
Construct More Complicated Arrays¶
use array_macro::array;
let arr: [usize; 5] = std::array::from_fn(|i| i);
arr
static arr2: [usize; 5] = std::array::from_fn(|i| i);
arr2
let arr: [Vec<usize>; 2] = {
let v = vec![
vec![1, 2, 3],
vec![4, 5, 6],
];
std::array::from_fn(|i| v[i].clone())
};
arr
let v = ["apples", "cake", "coffee"];
for text in v {
println!("I like {}.", text);
}
let v = ["apples".to_string(), "cake".to_string(), "coffee".to_string()];
for text in &v {
println!("I like {}.", text);
}
The size of the array must be determined at compile time.
let n = 5;
n
let arr2: [i32; n] = [0; n];
arr
let numbers = [0, 1, 2, 3];
numbers
numbers[0]
numbers[3]
for i in 1..3 {
println!("{}", numbers[i])
}
capacity¶
An array does not have the method capacity
since it is of fixed length.
numbers.capacity()
len¶
numbers.len()
push¶
numbers.push(4)
Size (in Bytes) of Array¶
std::mem::size_of_val(&numbers)
Iterate Through an Array¶
for loop / into_iter¶
let array: [i32; 3] = [0; 3];
for x in array {
println!("{}", x);
}
let words = vec!["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);
let words = ["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);
array.into_iter().map(|&i| array[i as usize]).sum::<i32>()
array.iter().map(|&i| array[i as usize]).sum::<i32>()
Using Array Index¶
for i in 0..5 {
println!("{}", numbers[i]);
}
Using the .iter()
Method¶
Technically speaking,
an array is coerced to a slice (implicitly) before calling .iter()
.
for n in numbers.iter() {
println!("{}", n);
}
Using the .iter_mut
Method¶
This is similar to the .iter()
method but allows you to update the array while iterate through it.
let mut numbers: [i32; 5] = [0, 1, 2, 3, 4];
for n in numbers.iter_mut() {
*n *= 2;
}
println!("{:?}", numbers);
Iterator¶
map
collect
group_by
2-D Array¶
let mut state = [[0u8; 4]; 6];
state[0][1] = 42;
state
Array vs Slice¶
An array is a collection of objects of the same type T
,
stored in contiguous memory.
Arrays are created using brackets []
,
and their length,
which is known at compile time,
is part of their type signature [T; length].
Slices are similar to arrays, but their length is not known at compile time. Instead, a slice is a two-word object, the first word is a pointer to the data, and the second word is the length of the slice. The word size is the same as usize, determined by the processor architecture eg 64 bits on an x86-64. Slices can be used to borrow a section of an array, and have the type signature &[T]
.