元组是存放多种不同类型数值的集合。元组通过圆括号 () 创建,每一个元组本身都是一个独立的值,它的类型标记写作 (T1, T2, ...),其中 T1、T2 代表元组内各个成员的类型。函数可以利用元组返回多个结果,因为单个元组能够承载任意个数的数据。
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)
配套知识点
- 元组式结构体:结构体名称后紧跟圆括号 ,括号里面是类型列表,没有字段名,只是靠顺序区分元素;
#[derive(Debug)]派生宏:自动为结构体实现Debug特征,支持用{:?}打印调试信息;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
总结
- 元组核心特性:允许同时存放不同类型数据(无符号整数、有符号整数、浮点数、字符、布尔值可共存);
- 元组索引语法:
元组变量.数字,索引从 0 开始;.0取第一个元素,.1取第二个元素;
- 索引只能写固定数字字面量,不能使用变量充当索引。
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
总结
- 支持多层元组嵌套,外层元组的元素可以是子元组;
- 元素数量≤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)
总结
- 普通二元元组可直接作为实参传入接收元组的函数;
- 函数返回全新元组,原元组
pair不会被修改。
7. 单元素元组特殊逗号规则(易错地方)
fn main() {
// 创建单元素元组时必须加逗号,用来区分它和单纯被括号包裹的普通字面量
println!("One element tuple: {:?}", (5u32,));
println!("Just an integer: {:?}", (5u32));
}Code language: JavaScript (javascript)
总结
(5u32,):末尾带逗号,是合法单元素元组,类型(u32,);(5u32):无逗号,仅等价于普通数字5u32,只是用括号包裹,不是元组;- 逗号是区分单元素元组与括号表达式的唯一标识。
8. 完整解构多元元组(参考上面)
// 元组可以完整解构,一次性绑定多个变量
let tuple = (1, "hello", 4.5, true);
let (a, b, c, d) = tuple;
println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
Code language: JavaScript (javascript)
总结
- 任意长度元组都能整体解构,左侧变量数量必须和元组元素数量完全匹配;
- 解构后每个变量独立对应元组对应位置的值,可单独使用。
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, 值2, ...); - 因为添加了
#[derive(Debug)],结构体支持{:?}调试打印。
Previous: 字面量与运算符