Memory Abstractions and Ownership
A game!
Conflicting mutability requirements!
Vec<T>
?Vec<bool>
?[bool; N*N]
What defines a contiguous sequence of elements on the hardware-level?
begin
and end
begin
, length
[T]
is a slice of elements of type T
begin
+ length
&[T]
and &mut [T]
begin
+ length
instead of begin
+ end
?[…] The length form keeps the metadata compact: one pointer-sized value plus one integer. Two pointers double the number of pointer-sized values. On 64-bit systems this saves 8 bytes per slice.
Vec<T>
capacity
?capacity
== No way of changing the sizeCopy
)fn main() {
let numbers: [u32; 4] = [1, 2, 3, 4];
// Slicing by passing a range `a..b` to the [] operator:
// `..` is the unbounded (i.e. full) range
let numbers_slice: &[u32] = &numbers[..];
// Slices behave like arrays:
// They have a len() method and support the [] operator:
println!("{}", numbers_slice.len());
println!("{}", numbers_slice[0]);
// We can even loop over slices:
for number in numbers_slice {
println!("{}", number);
}
}
fn count_whites(board: &[bool]) -> usize {
// ...
}
fn scramble(board: &mut [bool]) {
// ...
}
fn main() {
let mut board = gen_board();
let split_point = 4;
let counting_region = &board[..split_point];
let scrambling_region = &mut board[split_point..];
// Not real syntax, imagine the two functions run in parallel!
in_parallel! {
scramble(scrambling_region);
count_whites(counting_region);
}
}
fn count_whites(board: &[bool]) -> usize {
// ...
}
fn scramble(board: &mut [bool]) {
// ...
}
fn main() {
let mut board = gen_board();
let split_point = 4;
let counting_region = &board[..split_point];
let scrambling_region = &mut board[split_point..];
// Not real syntax, imagine the two functions run in parallel!
in_parallel! {
scramble(scrambling_region);
count_whites(counting_region);
}
}
Doesn’t compile :(
cannot borrow `board` as mutable because it is also borrowed as immutable
use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
fn count_whites(board: &[bool]) -> usize {
// ...
}
fn scramble(board: &mut [bool]) {
// ...
}
fn main() {
let mut board = gen_board();
let split_point = 4;
let (counting_region, scrambling_region) = board.split_at_mut(split_point);
// Not real syntax, imagine the two functions run in parallel!
in_parallel! {
scramble(scrambling_region);
count_whites(counting_region);
}
}
chunks_mut
to split into disjunct rows!Come up with a visual classification of these types: Vec<T>
, &[T]
, &mut [T]
Which core concepts can you isolate, and is there a gap for a type that we might not yet have covered in this classification?
10 minutes in groups (3-4)
ImmutableVec<T>
[T; N]
because arrays need a size known at compile-time!Vec
implies growing…Box<T>
T
on the heaplet val1 = 42;
let val2 = Box::new(42);
val2
holds a pointer)Box<T>
is a language itemBox<T>
!Box<T>
Box<T>
:What does it print?
5
What does it print?
6
What does it print?
4
What does it print?
8
Welcome to UTF-8!
Learn more here
String
is basically a Vec<u8>
with special semantics
String::len
returns the number of bytes, not the number of characters or graphemeschar
, which represents one Unicode scalar value (basically a character)
String::chars
gives you an iterator over all the characters in a stringThis prints:
👋 🏽
[T]
for general slices, there is str
for string slices
[u8]
but always valid UTF-8!Usage | Owning | Non-owning |
---|---|---|
Arbitrary type | Vec<T> |
[T] |
UTF-8 text | String |
str |
File system path | PathBuf |
Path |
… |