タプルとは、複数の異なる型の値を格納する集合です。丸括弧 () で作成し、各タプル自体が独立した値となります。型表記は (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) は完全な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)
関連知識ポイント
- タプル型構造体:構造体名の後に丸括弧を続け、括弧内に型リストを記述。フィールド名はなく、要素の順番のみで区別;
#[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で2番目の要素を取得;
- インデックスには固定の数値リテラルのみ記述可能、変数をインデックスにできない。
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
まとめ
- 複数層のタプル入れ子に対応、外側タプルの要素はサブタプルにできる;
- 要素数が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)
まとめ
- 通常の2要素タプルはタプルを受け取る関数に実引数として直接渡せる;
- 関数は全新しいタプルを返すため、元のタプル
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: リテラルと演算子