8.7 Using Slices and Tuples with Functions
Slices and tuples are common data structures in Rust, frequently used as function parameters and return types. String slices were already introduced as useful function parameter types in Section 6.5.5.
8.7.1 Slices (&[T]
and &str
)
Slices provide a view into a contiguous sequence of elements, representing all or part of data structures like arrays, Vec<T>
s, or String
s, without taking ownership. Passing slices is efficient as it only involves passing a pointer and a length.
String Slices (&str
): Used for passing views of string data.
// Takes a string slice and returns the first word (also as a slice). fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &item) in bytes.iter().enumerate() { if item == b' ' { return &s[0..i]; // Return slice up to the space } } &s[..] // Return the whole string slice if no space is found } fn main() { let sentence = String::from("Hello beautiful world"); let word = first_word(&sentence); // Pass reference to the String println!("The first word is: {}", word); // Output: The first word is: Hello let literal = "Another example"; let word2 = first_word(literal); // Works directly with string literals (&str) println!("The first word is: {}", word2); // Output: The first word is: Another }
Array/Vector Slices (&[T]
): Used for passing views of arrays or vectors containing elements of type T
.
// Calculates the sum of elements in an i32 slice. fn sum_slice(slice: &[i32]) -> i32 { let mut total = 0; for &item in slice { // Iterate over the elements in the slice total += item; } total } fn main() { let numbers_array = [1, 2, 3, 4, 5]; let numbers_vec = vec![10, 20, 30]; println!("Sum of array: {}", sum_slice(&numbers_array[..])); println!("Sum of part of vec: {}", sum_slice(&numbers_vec[1..])); }
Remember that when returning slices, lifetimes must ensure the reference remains valid (as discussed in Section 8.4.3).
As noted in Section 6.5.6, mutable slice parameters (&mut [T]
) are also permitted. Functions can modify the contents of the slice, but not its length. For string slices (&mut str
), an additional constraint is that all allowed modifications must preserve valid UTF-8 encoding.
8.7.2 Tuples
Tuples are fixed-size collections of values of potentially different types. They are useful for grouping related data, especially for returning multiple values from a function.
Tuples as Parameters:
// Represents a 2D point. type Point = (i32, i32); fn display_point(p: Point) { println!("Point coordinates: ({}, {})", p.0, p.1); // Access elements by index } fn main() { let my_point = (10, -5); display_point(my_point); }
Tuples as Return Types: Commonly used to return multiple results without defining a dedicated struct.
// Calculates sum and product, returning them as a tuple. fn calculate_stats(a: i32, b: i32) -> (i32, i32) { (a + b, a * b) // Return a tuple containing sum and product } fn main() { let num1 = 5; let num2 = 8; let (sum_result, product_result) = calculate_stats(num1, num2); // Destructure the returned tuple println!("Numbers: {}, {}", num1, num2); println!("Sum: {}", sum_result); println!("Product: {}", product_result); }