タプル
タプルは,複数の変数をまとめて一つの変数として扱えるようにしたものです.
fn main() {
let tuple: (i32, f64, i32) = (10, 2.5, 20);
println!("1 番目の要素:{}", tuple.0);
println!("2 番目の要素:{}", tuple.1);
println!("3 番目の要素:{}", tuple.2);
}
tuple
という変数があり,型は (i32, f64, i32)
,代入された値は (10, 2.5, 20)
となっています.
こうすると, tuple.0
, tuple.1
, tuple.2
という 3 つの変数が使えるようになります.数え方が .1
.2
.3
……ではなく .0
.1
.2
……であることに注意してください.
tuple.0
tuple.1
tuple.2
……の型は,それぞれ括弧の中の 1 番目, 2 番目, 3 番目……の型になります.今回は tuple
の型が (i32, f64, i32)
なので, tuple.0
の型が i32
で, tuple.1
の型が f64
で, tuple.2
の型が i32
です.
tuple.0
tuple.1
tuple.2
……の値も,それぞれ括弧の中の 1 番目, 2 番目, 3 番目……の値になります.今回は tuple
の値が (10, 2.5, 20)
なので, tuple.0
の値が 10
で, tuple.1
の値が 2.5
で, tuple.2
の値が 20
です.
よって,出力は 1 番目の要素:10
2 番目の要素: 2.5
3 番目の要素:20
となります.
(10, 2.5, 20)
は,最後にもう一つカンマを付けて (10, 2.5, 20,)
としても同じです.
ここで問題です.i32
型の変数は i64
型の変数は (i32, i64)
型の変数は何通りの値をとることができるでしょうか?
答え
i32
,i64
のとりうる値の集合をそれぞれ (i32, i64)
は直積
パターンマッチ
let
を使って変数を宣言するとき,今まで次のような書き方をしていました.
let 変数名: 型 = 式;
実は, let
の後には,単なる変数名だけでなく,パターンを書くことができます.
タプルの形をしたタプルパターンもその一つです.
fn main() {
let tuple = (10, 2.5);
let (x, y) = tuple;
assert_eq!(x, 10);
assert_eq!(y, 2.5);
}
let
の後に,タプルと同じ形式で (x, y)
と書かれています.こう書くと, =
の右辺のタプルの要素が,それぞれ x
,y
に代入されます.これをパターンマッチといいます.
今回は 1 つめの 10 が x
に, 2 つめの 2.5 が y
にそれぞれ代入されるので,続く 2 つの assert_eq!
は両方成功して,プログラムは正常終了します.
コードの中で,「x
の値が 10, y
の値が 2.5 になっている」ことを説明するために assert_eq!
マクロを使いました.この本では,このように説明としてアサートを使うことがあります.登場したら,「アサートの条件が成り立っていて,実行すると正常終了する」という意味で読んでください.
パターンの形式が右辺と合っていないようなものは,
fn main() {
let (x, y) = 10;
let (p, q, r) = (10, 20);
}
エラーになります.
error[E0308]: mismatched types
--> src/main.rs:2:9
|
2 | let (x, y) = 10i32;
| ^^^^^^ ----- this expression has type `i32`
| |
| expected `i32`, found tuple
|
= note: expected type `i32`
found tuple `(_, _)`
error[E0308]: mismatched types
--> src/main.rs:3:9
|
3 | let (p, q, r) = (10i32, 20i32);
| ^^^^^^^^^ -------------- this expression has type `(i32, i32)`
| |
| expected a tuple with 2 elements, found one with 3 elements
|
= note: expected tuple `(i32, i32)`
found tuple `(_, _, _)`
mismatched types
は,「型が合っていない」という意味です. this expression has type `i32`
は「この式は i32
型である」, expected `i32`, found tuple
は「i32
が来るはずだったが,実際にはタプルパターンがあった」という意味です.expected a tuple with 2 elements, found one with 3 elements
は,「要素が 2 つのタプルパターンが来るはずだったが,実際には要素が 3 つのタプルパターンだった」という意味です.
型注釈を付けるときは次のようになります.
fn main() {
let (c, g): (i32, f64) = (299792458, 6.67430e-11);
assert_eq!(c, 299792458_i32);
assert_eq!(g, 6.67430e-11_f64);
}
タプルを返すブロック
次のコードを見てみましょう.
use proconio::input;
fn main() {
input! {
a: i32,
b: i32,
}
let (max, min) = if a > b { (a, b) } else { (b, a) };
assert!(max >= min);
println!("大きい方:{}", max);
println!("小さい方:{}", min);
}
まず標準入力で 2 つの数 if
式が何を返しているか見てください. (max, min)
で受け取っています.よって, max
の値は min
の値は小さい方となります.
このように,タプルを使うことで,ブロックが 2 つの値を同時に返すことができます.
ユニット
ブロックの最後に式を書くことで,値を返すことができるのでした.
実は,ブロックの最後に式を書かないときもある値が返されています.それは,要素が 0 個のタプル ()
です.ユニットともいいます.
fn main() {
let unit: ();
unit = {
println!("() を返すブロック");
};
assert_eq!(unit, ());
}
括弧 (
… )
の中が空なので,型も ()
で値も ()
です.要素が無いため, ()
型の変数は, ()
という 1 通りの値を取ることしかできません.