We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ground Rules: Values, Types, Control Flow step 19 of 24
Arrays: the length is part of the type
Rotate a fixed five-element array left by by positions and return the result.
pub fn rotate_fixed(input: [i32; 5], by: usize) -> [i32; 5]
([1, 2, 3, 4, 5], 2) gives [3, 4, 5, 1, 2]. by = 0 and by = 5 are the
identity. by = 7 behaves like by = 2 — rotations wrap.
The starter does not compile, and its error is the definition of the item.
[i32; 5] and [i32; 6] are different types
An array’s length is part of its type. Not metadata, not a runtime field —
part of the type, checked at compile time, and [i32; 5] is no more
assignable to [i32; 6] than i32 is to String. That is why the starter’s
Vec<i32> cannot be returned from a function declared -> [i32; 5]:
E0308: expected [i32; 5], found Vec<i32>.
That 5 is a const generic parameter — the length is a compile-time value
the type is generic over — and for most learners this is the first one they
meet. It is why impl<T, const N: usize> … appears all over the standard
library, and why arrays only recently gained traits for arbitrary lengths.
The upside is real: an array’s size is known at compile time, so it lives
inline — in a local, in a struct field, in a register — with no heap allocation,
no pointer to follow and no length to store. size_of::<[i32; 5]>() is exactly
20 bytes.
The array / Vec / slice trio, in one paragraph
Three types that all “hold a run of T“, and are not arbitrary once you see
the axis they differ on:
-
[T; N]— length fixed at compile time, stored inline,CopyifTis. -
Vec<T>— length chosen and changed at run time, stored on the heap, owns its buffer. 24 bytes of pointer, length, capacity. -
&[T]— a view of a run ofTthat you do not own, with the length carried alongside the pointer. 16 bytes. Both of the above coerce to it.
Item 1.20 and item 1.21 take the other two in turn.
Copy, and why let mut out = input; works
[i32; 5] is Copy, because i32 is Copy and arrays inherit it. So
let mut out = input;
does not move input away — it copies all twenty bytes, and both bindings stay
usable. That is the whole of Track 1’s mental model, and it is exactly what
Track 2 will take away from you the moment the element type stops being Copy.
Once you have your own copy, [T]::rotate_left(n) does the work in place. Its
sibling rotate_right exists too. Both panic if n is greater than the
length, which is why by needs reducing before you hand it over.
Do not try to index out of bounds on purpose
let a = [1, 2, 3];
let x = a[5]; // error: this operation will panic at runtime
That is a compile error, not a runtime panic: it is the deny-by-default
unconditional_panic lint, and it fires whenever the compiler can evaluate the
index and see it is out of range. An index that came in through a parameter is
opaque to that analysis and panics at run time instead. Same rule you met with
constant arithmetic overflow in item 1.5 — Rust catches what it can see.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.