Problem overview
The function first_n receives a vector of integers, nums, and a number n. It returns a new vector holding the first n numbers of nums, in the same order. When n is 0 the result is empty, and n is never larger than the length of nums.
For nums = [3, 8, 1, 9, 4] and n = 3, the answer is [3, 8, 1]: the 9 and the 4 are left out. For nums = [2, 4] and n = 2, every number is kept.
Approach
The first n items sit at indexes 0 up to n - 1. A range of indexes selects exactly those, and to_vec() copies them into a new vector. You don't need a loop, and no index arithmetic beyond the range itself.
Step by step
- Take the range
0..nofnums. A Rust range stops before its end, so0..ncovers exactlynindexes. The parameternis ausize, the type Rust uses for indexes, so it fits in the range as it is, with no conversion. - Call
to_vec()on that slice. On its own,nums[0..n]only borrows part ofnumsand has no fixed size known at compile time, so it can't be returned.to_vec()makes an ownedVec<i32>. Store it inresult. - End the function with
resulton its own line, without a semicolon. Rust returns the last expression of a function body.
The solution in Rust
impl Solution {
fn first_n(nums: Vec<i32>, n: usize) -> Vec<i32> {
let result = nums[0..n].to_vec();
result
}
}
Writing result; with a semicolon would turn the last line into a statement, and the function would then return nothing, which is a compile error since a Vec<i32> is expected. When n is 0 the range 0..0 is empty, and to_vec() gives an empty vector without any special case.
Following one call
Take nums = [3, 8, 1, 9, 4] and n = 3. The slice nums[0..n] holds [3, 8, 1] and has length 3. After to_vec(), result is the vector [3, 8, 1], and nums is still [3, 8, 1, 9, 4]. The input is not changed, which is why the function can take nums without mut. Because the function owns nums anyway, it could also shorten the vector in place with truncate(n), but copying the front part is the idea this lesson practises.
Why not a loop
A loop that pushes nums[i] into a new vector for each i from 0 to n - 1 gives the same answer, and it is a fine exercise. The slice does the same work in one expression and cannot get the bounds wrong halfway. In Rust, a range with to_vec() is the usual way to copy a block of consecutive items, so it is worth learning as a single idea: pick a range, then copy.
Edge cases and common mistakes
- Off by one.
0..=nincludes indexnand returns one number too many (and panics whennequals the length). - A range past the end. The constraints keep
nwithin the length, so the code needs no guard. Without that promise,nums[0..n]withntoo large would panic. - Returning the slice. Leaving out
to_vec()gives a type mismatch, because the function must return an owned vector.
Testing
These results come from running the function on the statement's examples:
nums = [3, 8, 1, 9, 4],n = 3gives[3, 8, 1].nums = [5, 6, 7],n = 0gives[].nums = [2, 4],n = 2gives[2, 4].
