Tuples

# Tuples

A tuple is a collection that stores values of multiple distinct types. Tuples are created using parentheses (). Every tuple itself is a standalone value, with its type notation written as (T1, T2, ...), where T1 and T2 represent the type of each member inside the tuple. Functions can return multiple outputs with tuples, as a single tuple can hold any number of data entries.

1 Tuples as Function Parameters and Return Values

// Tuples can be used both as function inputs and return values
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // let can destructure tuple members and bind them to separate variables
    let (int_param, bool_param) = pair;
    // Return a new tuple with swapped order
    (bool_param, int_param)
}

fn main(){
    // (12, true) is a complete two-element tuple, passed as one single argument
	let res = reverse((12, true));
	// Use .0 index to fetch the first element of the returned tuple
	println!("{}", res.0);
}Code language: JavaScript (javascript)

Compilation and execution output

E:\rustdemo\demo>rustc demo.rs

E:\rustdemo\demo>demo
trueCode language: JavaScript (javascript)

2 Tuple Struct Definition

#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

fn main(){
    let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
    println!("{:?}", matrix);
}Code language: PHP (php)

Tuple structs: The struct name is followed directly by parentheses containing a list of types. There are no named fields, elements are only distinguished by their order;

The derive macro #[derive(Debug)]: Automatically implements the Debug trait for the struct, enabling debug print output with {:?};

Matrix(f32,f32,f32,f32) is essentially a special tuple wrapping four floating-point numbers.

A warning will appear during execution, which can be safely ignored

E:\rustdemo\demo>rustc demo.rs
warning: fields `0`, `1`, `2`, and `3` are never read
 --> demo.rs:2:15
  |
2 | struct Matrix(f32, f32, f32, f32);
  |        ------ ^^^  ^^^  ^^^  ^^^
  |        |
  |        fields in this struct
  |
  = help: consider removing these fields
  = note: `Matrix` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
  = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: 1 warning emitted


E:\rustdemo\demo>demo
Matrix(1.1, 1.2, 2.1, 2.2)Code language: JavaScript (javascript)

3 Long Mixed-Type Tuples + Value Access via Indexes

Take a look at the example below

fn main(){

    // A long tuple containing multiple different data types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Internal values can be retrieved using tuple indexes
    println!("Long tuple first value: {}", long_tuple.0);
    println!("Long tuple second value: {}", long_tuple.1);
}Code language: JavaScript (javascript)

Supports storing different data types simultaneously (unsigned integers, signed integers, floats, characters and booleans can coexist);

Tuple index syntax: tuple_variable.number, indexes start from 0;

  • .0 accesses the first element,
  • .1 accesses the second element;
  • and so on….

Indexes can only be fixed numeric literals; variables cannot be used as indexes.

Unorganized content below——

2. Tuple Struct Definition


// The struct below is for after-class exercises
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
Code language: PHP (php)

Related Knowledge Points

  1. Tuple struct: The struct name is followed by parentheses with a list of types inside. There are no field names, elements are distinguished only by order;
  2. The derive macro #[derive(Debug)]: Automatically implements the Debug trait for the struct, allowing debug printing with {:?};
  3. Matrix(f32,f32,f32,f32) is essentially a special tuple wrapping four floating-point numbers.

Full example below

#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

fn main() {
    // 1. Create an instance
    let mat = Matrix(1.0, 2.0, 3.0, 4.0);

    // 2. Print (#[derive(Debug)] is required to use {:?})
    println!("Matrix instance: {:?}", mat);

    // 3. Access internal elements via .index
    let a = mat.0;
    let b = mat.1;
    let c = mat.2;
    let d = mat.3;
    println!("a={}, b={}, c={}, d={}", a, b, c, d);

    // 4. Destructuring to get values
	// Matrix(m0, m1, m2, m3) is a destructuring pattern match. m0/m1/m2/m3 are custom temporary variables to store the four tuple members inside the struct.
    let Matrix(m0, m1, m2, m3) = mat;
    println!("Destructure: {} {} | {} {}", m0, m1, m2, m3);
	

    // 5. Mutable matrix, modify elements with mut keyword
    let mut mat_mut = Matrix(0.0, 0.0, 0.0, 0.0);
    mat_mut.0 = 10.0;
    mat_mut.3 = 99.0; // Values can be modified
    println!("Mutable matrix: {:?}", mat_mut);
}Code language: PHP (php)

Execution output

E:\rustdemo\demo>demo
Matrix instance: Matrix(1.0, 2.0, 3.0, 4.0)
a=1, b=2, c=3, d=4
Destructure: 1 2 | 3 4
Mutable matrix: Matrix(10.0, 0.0, 0.0, 99.0)

3. Long Mixed-Type Tuples + Value Access via Indexes

fn main() {
 
    // A long tuple containing multiple different data types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using tuple indexing.
    println!("Long tuple first value: {}", long_tuple.0);
    println!("Long tuple second value: {}", long_tuple.1);
}
Code language: JavaScript (javascript)

Execution output

E:\rustdemo\demo>demo
Long tuple first value: 1
Long tuple second value: 2

Summary

  1. Core feature of tuples: supports storing different data types simultaneously (unsigned integers, signed integers, floats, characters and booleans can coexist);
  2. Tuple index syntax: tuple_variable.number, indexes start from 0;
    • .0 accesses the first element,
    • .1 accesses the second element;
  3. Indexes can only be fixed numeric literals; variables cannot be used as indexes.

4. Nested Tuples

fn main() {
 
    // Tuple members can themselves be tuples; nesting is supported
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

 
    // Tuples support debug printing
    println!("tuple of tuples: {:?}", tuple_of_tuples);
	
	// Chain two . accessors to fetch nested values
	println!("tuple of tuples: {:?}", tuple_of_tuples.0.1); // Outputs 2
}
Code language: JavaScript (javascript)

Output

E:\rustdemo\demo>demo
tuple of tuples: ((1, 2, 2), (4, -1), -2)
tuple of tuples: 2

Summary

  1. Multi-level tuple nesting is supported; elements of outer tuples can be child tuples;
  2. Tuples with ≤12 elements automatically implement the Debug trait; the format specifier {:?} can print all contents directly.

5. Print Restriction for Over-Long Tuples (Compile Error)


   fn main() {
 
    // Tuples with more than 12 elements cannot be printed directly with Debug
    let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
    println!("Too long tuple: {:?}", too_long_tuple);
    // Tip: Uncomment the two lines above to view the compiler error
}
Code language: JavaScript (javascript)

Compile error log

E:\rustdemo\demo>rustc demo.rs
error[E0277]: `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})` doesn't implement `Debug`
 --> demo.rs:5:38
  |
5 |     println!("Too long tuple: {:?}", too_long_tuple);
  |                               ----   ^^^^^^^^^^^^^^ `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})` cannot be formatted using `{:?}` because it doesn't implement `Debug`
  |                               |
  |                               required by this formatting parameter
  |
  = help: the trait `Debug` is not implemented for `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})`
  = help: the following other types implement trait `Debug`:
            ()
            (A, Z, Y, X, W, V, U, T)
            (B, A, Z, Y, X, W, V, U, T)
            (C, B, A, Z, Y, X, W, V, U, T)
            (D, C, B, A, Z, Y, X, W, V, U, T)
            (E, D, C, B, A, Z, Y, X, W, V, U, T)
            (T,)
            (U, T)
          and 5 others
  = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.Code language: PHP (php)

Summary

The Rust standard library only auto-derives the Debug trait for tuples with 0~12 elements;

Tuples with more than 12 elements have no built-in Debug implementation, and direct printing with {:?} will fail compilation.

You can delete the number 13 above and test it to see if the error disappears

6. Call Functions With Tuple Parameters & Observe Swapped Output

// Tuples can be used both as function inputs and return values
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // let can destructure tuple members and bind them to separate variables
    let (int_param, bool_param) = pair;
    // Return a new tuple with swapped order
    (bool_param, int_param)
}

fn main() {
 
    let pair = (1, true);
    println!("Pair is {:?}", pair);

    println!("The reversed pair is {:?}", reverse(pair)); // Call reverse to swap elements
}Code language: JavaScript (javascript)

Execution output

E:\rustdemo\demo>demo
Pair is (1, true)
The reversed pair is (true, 1)Code language: JavaScript (javascript)

Summary

  1. Standard two-element tuples can be passed directly as arguments to functions accepting tuple inputs;
  2. The function returns a brand new tuple; the original pair tuple remains unmodified.

7. Special Comma Rule for Single-Element Tuples (Common Pitfall)


   fn main() {
 
    // A trailing comma is mandatory when creating single-element tuples, to distinguish them from regular literals wrapped only in parentheses
    println!("One element tuple: {:?}", (5u32,)); 
    println!("Just an integer: {:?}", (5u32));

}Code language: PHP (php)

Summary

  1. (5u32,): Trailing comma present, this is a valid single-element tuple with type (u32,);
  2. (5u32): No comma, this is just equivalent to the regular number 5u32 wrapped in parentheses, not a tuple;
  3. The comma is the only marker to tell single-element tuples apart from parenthesized expressions.

8. Full Destructuring of Multi-Element Tuples (Reference Above)


    // Tuples can be fully destructured to bind multiple variables at once
    let tuple = (1, "hello", 4.5, true);

    let (a, b, c, d) = tuple;
    println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
Code language: JavaScript (javascript)

Summary

  1. Tuples of any length support full destructuring; the number of variables on the left must exactly match the number of tuple elements;
  2. After destructuring, each variable holds the value from its matching position in the tuple and can be used independently.

9. Tuple Struct Instantiation & Debug Printing

#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

fn main() {
 
    let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
    println!("{:?}", matrix);

}Code language: PHP (php)

Summary

  1. Tuple struct instantiation syntax: StructName(value1, value2, ...);
  2. With #[derive(Debug)] added, the struct supports debug printing via {:?}.

Leave a Reply

Your email address will not be published. Required fields are marked *