元组 Tuples

元组是存放多种不同类型数值的集合。元组通过圆括号 () 创建,每一个元组本身都是一个独立的值,它的类型标记写作 (T1, T2, ...),其中 T1T2 代表元组内各个成员的类型。函数可以利用元组返回多个结果,因为单个元组能够承载任意个数的数据。

1 元组可作为函数参数、函数返回值

// 元组既可以用作函数入参,也可以用作函数返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // let 可以将元组内部成员解构绑定到独立变量
    let (int_param, bool_param) = pair;
    // 返回交换顺序后的新元组
    (bool_param, int_param)
}

fn main(){
    // (12, true) 是一个完整二元元组,作为单个参数传入
	let res = reverse((12, true));
	// 用 .0 索引取返回元组第一个元素
	println!("{}", res.0);
}Code language: JavaScript (javascript)

编译和执行结果

E:\rustdemo\demo>rustc demo.rs

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

2 元组结构体(Tuple Struct)定义

#[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)

元组式结构体:结构体名称后紧跟圆括号 + 类型列表,无命名字段,仅靠顺序区分元素;

#[derive(Debug)] 派生宏:自动为结构体实现 Debug 特征,支持用 {:?} 打印调试信息;

Matrix(f32,f32,f32,f32) 本质是包装 4 个浮点数的特殊元组。

执行过程,有个警告,可以忽略

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 多类型混合长元组 + 下标索引取值

先看例子

fn main(){

    // 包含多种不同数据类型的长元组
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // 可以通过元组下标索引提取内部数值
    println!("Long tuple first value: {}", long_tuple.0);
    println!("Long tuple second value: {}", long_tuple.1);
}Code language: JavaScript (javascript)

允许同时存放不同类型数据(无符号整数、有符号整数、浮点数、字符、布尔值可共存);

元组索引语法:元组变量.数字,索引从 0 开始;

  • .0 取第一个元素,
  • .1 取第二个元素;
  • 以此类推….

索引只能写固定数字字面量,不能使用变量充当索引。

下面还没有整理的部分——

2. 元组结构体(Tuple Struct)定义


// 下方结构体是课后练习使用
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
Code language: PHP (php)

配套知识点

  1. 元组式结构体:结构体名称后紧跟圆括号 ,括号里面是类型列表,没有字段名,只是靠顺序区分元素;
  2. #[derive(Debug)] 派生宏:自动为结构体实现 Debug 特征,支持用 {:?} 打印调试信息;
  3. Matrix(f32,f32,f32,f32) 本质是包装 4 个浮点数的特殊元组。

下面是完整例子

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

fn main() {
    // 1. 创建实例
    let mat = Matrix(1.0, 2.0, 3.0, 4.0);

    // 2. 打印(因为加了 #[derive(Debug)] 才能用 {:?})
    println!("矩阵实例: {:?}", mat);

    // 3. 访问内部元素:用 .索引
    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. 解构取值
	// Matrix(m0, m1, m2, m3) 是解构模式匹配,m0/m1/m2/m3 自己定义的临时变量名,用来接收结构体内部 4 个元组成员的值。
    let Matrix(m0, m1, m2, m3) = mat;
    println!("解构:{} {} | {} {}", m0, m1, m2, m3);
	

    // 5. 可变矩阵,修改元素 使用mut
    let mut mat_mut = Matrix(0.0, 0.0, 0.0, 0.0);
    mat_mut.0 = 10.0;
    mat_mut.3 = 99.0; //可以修改
    println!("可变矩阵: {:?}", mat_mut);
}Code language: PHP (php)

执行结果

E:\rustdemo\demo>demo
矩阵实例: Matrix(1.0, 2.0, 3.0, 4.0)
a=1, b=2, c=3, d=4
解构:1 2 | 3 4
可变矩阵: Matrix(10.0, 0.0, 0.0, 99.0)

3. 多类型混合长元组 + 下标索引取值

fn main() {
 
    // 包含多种不同数据类型的长元组
    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)

执行结果

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

总结

  1. 元组核心特性:允许同时存放不同类型数据(无符号整数、有符号整数、浮点数、字符、布尔值可共存);
  2. 元组索引语法:元组变量.数字,索引从 0 开始;
    • .0 取第一个元素,
    • .1 取第二个元素;
  3. 索引只能写固定数字字面量,不能使用变量充当索引。

4. 元组嵌套

fn main() {
 
    // 元组的成员本身也可以是元组,支持嵌套
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

 
    // 元组支持调试打印
    println!("tuple of tuples: {:?}", tuple_of_tuples);
	
	//两次使用.输出
	println!("tuple of tuples: {:?}", tuple_of_tuples.0.1); //输出 2
}
Code language: JavaScript (javascript)

输出

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

总结

  1. 支持多层元组嵌套,外层元组的元素可以是子元组;
  2. 元素数量≤12 的元组自动实现 Debug,使用格式化符 {:?} 可直接打印完整内容。

5. 超长元组打印限制(编译报错)


   fn main() {
 
    // 但元素超过12个的超长元组无法直接使用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);
    // 提示:取消注释上面两行代码,就能看到编译器报错
}
Code language: JavaScript (javascript)

编译报错

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)

总结

Rust 标准库仅为元素数量 0~12 的元组自动派生 Debug 特征;

元素个数>12 的元组没有内置 Debug 实现,直接 {:?} 打印会编译失败。

读者可以把上面的13 删掉,然后试试,会不会出错

6. 调用元组参数函数、观察交换结果

// 元组既可以用作函数入参,也可以用作函数返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // let 可以将元组内部成员解构绑定到独立变量
    let (int_param, bool_param) = pair;
    // 返回交换顺序后的新元组
    (bool_param, int_param)
}

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

    println!("The reversed pair is {:?}", reverse(pair)); //调用上面的reverse 交换
}Code language: JavaScript (javascript)

执行结果

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

总结

  1. 普通二元元组可直接作为实参传入接收元组的函数;
  2. 函数返回全新元组,原元组 pair 不会被修改。

7. 单元素元组特殊逗号规则(易错地方)


   fn main() {
 
    // 创建单元素元组时必须加逗号,用来区分它和单纯被括号包裹的普通字面量
    println!("One element tuple: {:?}", (5u32,)); 
    println!("Just an integer: {:?}", (5u32));

}Code language: JavaScript (javascript)

总结

  1. (5u32,):末尾带逗号,是合法单元素元组,类型 (u32,)
  2. (5u32):无逗号,仅等价于普通数字 5u32,只是用括号包裹,不是元组
  3. 逗号是区分单元素元组与括号表达式的唯一标识。

8. 完整解构多元元组(参考上面)


    // 元组可以完整解构,一次性绑定多个变量
    let tuple = (1, "hello", 4.5, true);

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

总结

  1. 任意长度元组都能整体解构,左侧变量数量必须和元组元素数量完全匹配;
  2. 解构后每个变量独立对应元组对应位置的值,可单独使用。

9. 元组结构体实例化与 Debug 打印

#[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)

总结

  1. 元组结构体实例化语法:结构体名(值1, 值2, ...)
  2. 因为添加了 #[derive(Debug)],结构体支持 {:?} 调试打印。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注