Rust Slices Quiz

Rust
0 Passed
0% acceptance

40 comprehensive questions on Rust's slice types, covering borrowed views, indexing, mutable slices, ranges, and slice methods — with 11 code examples demonstrating practical slice usage patterns.

40 Questions
~80 minutes
1

Question 1

What is a slice in Rust and how does it differ from an array or vector in terms of memory ownership and allocation?

A
A slice is a borrowed reference to a contiguous sequence of elements in memory, without owning the data, while arrays and vectors own their data and manage memory allocation directly
B
A slice owns its data like an array but provides dynamic sizing like a vector
C
A slice is just another name for an array with variable length
D
Slices and arrays are identical in memory ownership and allocation
2

Question 2

How do you create a slice from an array and what is the syntax for specifying the range of elements you want to include?

A
Use &array[start..end] syntax where start is inclusive and end is exclusive
B
Use array.slice(start, end) method
C
Use array[start..=end] for inclusive ranges
D
Slices cannot be created from arrays directly
3

Question 3

What happens when you try to access a slice element using an index that is out of bounds, and how does this compare to array access?

A
Slice access panics at runtime just like array access, since both perform bounds checking
B
Slice access returns None while array access panics
C
Slice access is unchecked and can cause undefined behavior
D
Slice access cannot go out of bounds due to compile-time guarantees
4

Question 4

How do you safely access slice elements to avoid potential panics, and what type does the safe access method return?

A
Use get(index) method which returns Option<&T> to handle out-of-bounds gracefully
B
Use safe_get(index) which returns Result<&T, Error>
C
Use try_get(index) which throws an exception
D
Direct indexing with [] is always safe for slices
5

Question 5

What will this code output when executed, and why does it work the way it does?

rust
fn main() {
    let arr = [1, 2, 3, 4, 5];
    let slice = &arr[1..4];
    println!("Slice length: {}, first element: {}", slice.len(), slice[0]);
}
A
Slice length: 3, first element: 2 - because the slice includes elements at indices 1, 2, and 3 from the original array
B
Slice length: 4, first element: 1 - because slices copy the data
C
Compilation error - slices cannot be created from arrays
D
Slice length: 3, first element: 1 - because slice indexing starts from 0
6

Question 6

How do you create a mutable slice from a mutable array, and what operations become possible with a mutable slice that aren't possible with an immutable slice?

A
Use &mut array[start..end] which allows modifying elements through the slice reference
B
Use array.slice_mut(start, end) to get a mutable slice
C
Mutable slices cannot be created from arrays
D
Use &array[start..end] and cast to mutable
7

Question 7

What is the difference between slice.len() and slice.capacity() for slices created from arrays versus slices created from vectors?

A
For array slices, len() returns the slice length and capacity() doesn't exist; for vector slices, both exist but capacity refers to the vector's allocated space
B
Slices from arrays have capacity equal to len, while vector slices have separate capacity
C
All slices have both len() and capacity() methods
D
Slices don't have capacity, only length
8

Question 8

How do you iterate over all elements of a slice using a for loop, and what are the different ways to get mutable access during iteration?

A
Use for element in &slice for immutable, for element in &mut slice for mutable access to elements
B
Use for element in slice.iter() for immutable, slice.iter_mut() for mutable
C
Both A and B are correct approaches
D
Slices cannot be iterated with for loops
9

Question 9

What does the range syntax .. represent when creating slices, and how does it differ from ..= syntax?

A
.. is exclusive of end index while ..= is inclusive, so &arr[1..4] takes elements 1,2,3 while &arr[1..=4] would take 1,2,3,4
B
..= is exclusive while .. is inclusive
C
Both .. and ..= are inclusive of the end index
D
..= syntax doesn't exist in Rust
10

Question 10

How do you create a slice that includes all elements of an array or vector, and what is this commonly called?

A
Use &array[..] which creates a slice referencing the entire array
B
Use array.as_slice() method
C
Use &array which automatically converts to slice
D
All of the above work
11

Question 11

What will this code do and why might it be useful in practice?

rust
fn main() {
    let data = [10, 20, 30, 40, 50];
    let middle = &data[1..4]; // elements 20, 30, 40
    println!("Middle slice: {:?}", middle);
    
    // Can still access original array
    println!("First element: {}", data[0]);
}
A
Creates a view of elements 20, 30, 40 while keeping access to the full array, useful for working with portions of data without copying
B
Creates a copy of elements 1-4, losing access to the original array
C
Compilation error - cannot create overlapping references
D
Moves the middle elements out of the array
12

Question 12

How do slice methods like first() and last() work, and what do they return when called on an empty slice?

A
first() and last() return Option<&T>, returning None for empty slices to handle the absence of elements safely
B
They return &T directly and panic on empty slices
C
They return the middle element of the slice
D
These methods don't exist on slices
13

Question 13

What does the split_at() method do on a slice, and when might you use it instead of creating two separate slices?

A
Splits one slice into two at a given index, returning a tuple of slices, useful when you need both parts and want to avoid bounds checking
B
Splits the slice into individual elements
C
Splits on a delimiter like strings do
D
split_at() doesn't exist for slices
14

Question 14

How do you check if a slice contains a specific element, and what method would you use for more complex search conditions?

A
Use contains() for exact matches, iter().any() for complex conditions with closures
B
Use find() for both exact and complex searches
C
Use search() method with predicates
D
Slices don't have search methods
15

Question 15

What happens when you try to modify a slice element through a mutable slice reference, and how does this affect the original data source?

A
The modification affects the original data source since slices are views, not copies
B
The modification only affects the slice, not the original data
C
Slices cannot be modified
D
Modification creates a copy of the data
16

Question 16

How do you create a slice from a vector, and what is the relationship between the slice's lifetime and the vector's lifetime?

A
Use &vec[start..end] or &vec[..], and the slice cannot outlive the vector since it borrows from it
B
Use vec.slice(start, end) which creates an owned slice
C
Slices from vectors have independent lifetimes
D
Vectors cannot be sliced
17

Question 17

What does the chunks() method do on a slice, and how might it be useful for processing large datasets in fixed-size pieces?

A
Splits the slice into smaller slices of a specified size, useful for batch processing or working with fixed-size buffers
B
Compresses the slice into chunks of data
C
Creates overlapping chunks of elements
D
chunks() doesn't exist on slices
18

Question 18

How do you reverse the elements of a slice in place, and what type of slice reference do you need for this operation?

A
Use reverse() method on a mutable slice (&mut [T]) to reverse elements in place
B
Use rev() iterator adapter which creates a new reversed slice
C
Use reverse() on immutable slices
D
Slices cannot be reversed
19

Question 19

What is the difference between slice concatenation using iterators versus using the concat() method, and when would you choose one over the other?

A
Iterator chaining creates a new collection, concat() flattens nested slices into owned vector, choose based on whether you need ownership or just iteration
B
Both create new owned collections
C
concat() only works with strings
D
Slices cannot be concatenated
20

Question 20

How do you handle the case where you need to work with a slice but also need to know the total length of the original data structure it came from?

A
Keep track of the original reference alongside the slice, or use methods that return both the slice and metadata
B
Slices automatically include metadata about their source
C
Use len() on the slice which gives the original length
D
This information is not accessible when working with slices
21

Question 21

What will this code output and why does the borrowing work the way it does?

rust
fn main() {
    let mut data = [1, 2, 3, 4, 5];
    let slice1 = &mut data[0..3]; // mutable borrow of first 3 elements
    let slice2 = &data[2..5];    // immutable borrow of last 3 elements
    
    slice1[0] = 10;
    println!("slice2[0] = {}", slice2[0]); // This works!
}
A
slice2[0] = 3 - because the mutable and immutable borrows don't overlap in a way that violates Rust's borrowing rules
B
Compilation error - cannot have mutable and immutable borrows of the same data
C
slice2[0] = 10 - because the mutable borrow affects the immutable view
D
Runtime panic due to conflicting borrows
22

Question 22

How do you create a slice from a string literal, and what type does this create in Rust?

A
String literals are already &str slices, so let s: &str = "hello" creates a string slice directly
B
Use &"hello"[..] to create a slice from a string literal
C
String literals are String types, not slices
D
Both A and B work
23

Question 23

What does the windows() method do on a slice, and how does it differ from chunks() in terms of overlap between consecutive elements?

A
windows() creates overlapping windows of elements, while chunks() creates non-overlapping contiguous chunks
B
windows() creates non-overlapping windows
C
Both methods are identical
D
windows() doesn't exist on slices
24

Question 24

How do you sort a mutable slice in place, and what trait bounds are required on the element type?

A
Use sort() method which requires elements to implement Ord trait for total ordering
B
Use sort_by() with a custom comparator function
C
Both A and B are correct
D
Slices cannot be sorted
25

Question 25

What happens when you try to create a slice with invalid range bounds, such as negative indices or end before start?

A
Compilation error for invalid syntax, or runtime panic for out-of-bounds access during slice creation
B
Invalid ranges are automatically corrected
C
Empty slice is returned
D
The operation succeeds with undefined behavior
26

Question 26

How do you convert a slice to a vector, and when might you need to do this conversion?

A
Use to_vec() method or collect() on slice iterator, needed when you need ownership of the data or dynamic sizing
B
Use slice.as_vec() method
C
Automatic conversion happens when needed
D
Slices cannot be converted to vectors
27

Question 27

What does the binary_search() method do on a sorted slice, and what does it return for successful and unsuccessful searches?

A
Performs binary search returning Result<usize, usize> where Ok contains index of found element, Err contains insertion point
B
Returns Option<usize> with Some(index) for found, None for not found
C
Returns bool indicating if element exists
D
binary_search() doesn't exist on slices
28

Question 28

How do you create a slice that skips elements at the beginning or end of another slice, and what methods would you use for this?

A
Use range syntax &[start..end] or methods like split_first(), split_last(), strip_prefix(), strip_suffix()
B
Use skip() and take() iterator adapters
C
Use trim_start() and trim_end() methods
D
Slices cannot be trimmed or have elements removed
29

Question 29

What is the relationship between slices and the concept of 'fat pointers' in Rust's memory model?

A
Slices are fat pointers containing both a pointer to the data and the length of the slice
B
Slices are thin pointers like regular references
C
Slices don't use pointers at all
D
Fat pointers are only used for trait objects
30

Question 30

How do you handle slices of different types in generic functions, and what trait bounds might you need?

A
Use &[T] as parameter type, possibly with trait bounds like T: Ord for sorting operations
B
Use generic <T> parameter without slice syntax
C
Slices cannot be used in generic functions
D
Use Any trait for type-erased slices
31

Question 31

What will this code demonstrate about slice borrowing rules?

rust
fn main() {
    let mut data = [1, 2, 3, 4, 5];
    let slice = &mut data[..]; // mutable borrow of entire array
    
    // This would fail:
    // let another = &data[0]; // immutable borrow while mutable borrow exists
    
    slice[0] = 10;
    println!("Modified: {}", slice[0]);
}
A
That a mutable slice borrow of the entire array prevents other borrows of any part of the array
B
That multiple mutable borrows are allowed as long as they don't overlap
C
That slice borrowing rules are different from regular borrowing
D
That this code compiles and runs without issues
32

Question 32

How do you implement a function that accepts any slice type, including both arrays and vectors, using generic programming?

A
Use fn process<T>(slice: &[T]) where T can be any type, allowing the function to work with any slice
B
Use fn process(slice: &[impl Any]) for type-erased slices
C
Use separate functions for arrays and vectors
D
This is not possible in Rust
33

Question 33

What does the rotate_left() and rotate_right() methods do on mutable slices, and when might you use these operations?

A
Rotate elements left or right by a specified amount, useful for implementing queues or shifting data in buffers
B
Sort elements in ascending or descending order
C
Reverse the order of elements
D
These methods don't exist on slices
34

Question 34

How do you compare two slices for equality, and what does the comparison check exactly?

A
Use == operator which compares elements pairwise using PartialEq, checking both length and contents
B
Use eq() method which only compares lengths
C
Use cmp() method for lexicographic comparison
D
Slices cannot be compared for equality
35

Question 35

What is the difference between slice::from_ref() and creating a slice directly with &value, and when would you use each approach?

A
from_ref() creates &[T; 1] from &T, while &value creates &[T] from owned value, use from_ref for single-element slices from references
B
They are identical and interchangeable
C
from_ref() only works with arrays
D
from_ref() doesn't exist in the standard library
36

Question 36

How do you handle slices in error-prone code where bounds checking might fail, and what patterns help make slice operations more robust?

A
Use get() instead of [] indexing, combine with pattern matching on Option/Result, use methods like get() and split_at() that return safe types
B
Use unchecked indexing with unsafe blocks
C
Add debug assertions for bounds checking
D
Slice operations are always safe by default
37

Question 37

What does the copy_from_slice() method do, and what are the requirements for it to work correctly?

A
Copies elements from one slice to another mutable slice, requiring both slices to have the same length and element types that implement Copy
B
Creates a copy of the slice as a new allocation
C
Copies elements from the slice to a vector
D
copy_from_slice() doesn't exist on slices
38

Question 38

How do you work with slices of slices (nested slices), and what types are involved in this pattern?

A
&[&[T]] for slice of slices, or &[[T]] for array of arrays, useful for jagged arrays or matrix operations
B
Use Vec<Vec<T>> for nested slice operations
C
Nested slices are not supported in Rust
D
Use [[[T]]] for three-dimensional slices
39

Question 39

What performance characteristics do slice operations have compared to operations on owned collections like Vec?

A
Slice operations are generally faster since they avoid allocation and copying, providing zero-cost abstraction
B
Slice operations are slower due to bounds checking
C
Performance is identical between slices and owned collections
D
Slices are always slower due to indirection
40

Question 40

In a complex algorithm that needs to process different overlapping views of the same data, how would you manage slice lifetimes and borrowing to avoid compilation errors?

A
Create slices in a nested scope so they don't overlap in lifetime, use non-lexical lifetimes to allow more flexible borrowing patterns, and consider using split_at() for safe division
B
Use Rc<RefCell<T>> to allow multiple mutable references
C
Copy the data for each slice to avoid borrowing issues
D
This level of complexity requires unsafe code

QUIZZES IN Rust