Rust - Tuple
Rust - Tuples
Section titled “Rust - Tuples”A tuple is a general-purpose, compound data type for grouping together a number of values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size.
They are useful when you want to combine a few related pieces of information without the overhead of creating a full struct.
Creating and Accessing Tuples
Section titled “Creating and Accessing Tuples”You create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a type, and the types of the different values in the tuple don’t have to be the same.
You can access a tuple element directly by using a period (.) followed by the index of the value you want to access. The first index is 0.
fn main() { // Creating a tuple with type annotations let user_data: (String, u32, bool) = (String::from("Alice"), 30, true);
// Accessing elements by index let user_name = &user_data.0; let user_age = user_data.1;
println!("User: {}, Age: {}", user_name, user_age);
// You can use the debug formatter `{:?}` to print the whole tuple println!("Full user data: {:?}", user_data);}Output
Section titled “Output”User: Alice, Age: 30Full user data: ("Alice", 30, true)Tuple Destructuring
Section titled “Tuple Destructuring”Destructuring is a convenient way to break a tuple up into its individual pieces. You can do this with a let pattern, which creates variables for each element of the tuple.
fn main() { let http_status = (404, "Not Found");
// Destructuring the tuple into two variables let (status_code, status_message) = http_status;
println!("The status code is {}", status_code); println!("The status message is '{}'", status_message);
// Note: the original tuple `http_status` is still available if its types // are `Copy`. If it contains non-Copy types like `String`, the values would be moved. println!("Original tuple: {:?}", http_status);}Output
Section titled “Output”The status code is 404The status message is 'Not Found'Original tuple: (404, "Not Found")Practical Use Cases for Tuples
Section titled “Practical Use Cases for Tuples”Returning Multiple Values from a Function
Section titled “Returning Multiple Values from a Function”A common and idiomatic use of tuples is to return multiple values from a function. This is often cleaner than returning a struct if the structure is simple and only used in one place.
// This function calculates the length and first word of a sentence.// It returns a tuple containing a usize and a String.fn calculate_length_and_first_word(s: String) -> (usize, String) { let length = s.len(); let first_word = s.split_whitespace().next().unwrap_or("").to_string(); (length, first_word) // Return the tuple}
fn main() { let sentence = String::from("Rust programming is fun");
let (len, word) = calculate_length_and_first_word(sentence);
println!("The sentence has {} bytes.", len); println!("The first word is '{}'.", word);
// Trying to use `sentence` here would fail, because it was moved into the function. // println!("{}", sentence); // Error: value borrowed here after move}When to Use a Tuple vs. a Struct
Section titled “When to Use a Tuple vs. a Struct”Tuples and structs are similar, but have different ideal use cases:
- Use a tuple when: You have a small, fixed-size collection of related but different-typed data, and the meaning of each element is clear from its position alone. Returning an error code and a result is a classic example.
- Use a struct when: Your data has more complexity. Giving each field a name makes the code more readable and maintainable. If you expect to pass this data structure around through multiple functions, a
structis almost always the better choice.
The Unit Type ()
Section titled “The Unit Type ()”There is a special tuple with no elements, written as (). This is called the unit type, and it has only one value, also written (). The unit type is implicitly returned by functions that don’t have an explicit -> return type. It signifies an empty or valueless return.
fn does_not_return_a_value() { println!("I return the unit type implicitly!");}
fn main() { let result = does_not_return_a_value(); // `result` here has the value `()` and the type `()` // This is not very useful, but demonstrates the concept.}