元組 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) 本質是包裝四個浮點數的特殊元組。

執行過程會出現一則警告,可直接忽略

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) 本質是包裝四個浮點數的特殊元組。

下方為完整範例

#[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 為自訂暫存變數,用來接收結構體內四個元組成員的值。
    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)] 後,結構體支援 {:?} 除錯列印。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *