タプル 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) は完全な2要素タプルで、単一の引数として渡す
	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番目の要素を取得;
  • 以降同様……

インデックスには固定の数値リテラルのみ記述可能で、変数をインデックスとして使用できません。

下記は未整理の部分——

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 で2番目の要素を取得;
  3. インデックスには固定の数値リテラルのみ記述可能、変数をインデックスにできない。

4. タプルの入れ子

fn main() {
 
    // タプルのメンバー自身もタプルにでき、入れ子に対応
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

 
    // タプルはデバッグ出力に対応
    println!("tuple of tuples: {:?}", tuple_of_tuples);
	
	// . を2回連続で使用して値を出力
	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() {
 
    // 要素が13個を超える超長タプルは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);
    // ヒント:上記2行のコメントを外すとコンパイラエラーが確認できる
}
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 トレイトを派生;

要素数が13以上のタプルには標準の 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要素タプルはタプルを受け取る関数に実引数として直接渡せる;
  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)] を記述することで、構造体が {:?} によるデバッグ出力に対応。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です