Rustは構文のレベルでパターンマッチングをする言語で、しかも至る所でそれが出てくるので、パターンマッチングを受け入れないとコードを読めるようにならない。
例えばmatch文。
fn main() { let x:i32=5; let y:i32=10; // 「(5 , 10) というパターン」 match (x,y){ // (5,10) の内容が 「(5,10)」 に一致する場合 (5,10)=> println!("Both x and y are 5 and 10, respectively."), // (5,10) の内容が 「(5,何でもいい)」 に一致する場合 (5,_)=> println!("x is 5, and y can be any value."), // (5,10) の内容が 「上記のパターン以外」 に一致する場合 _ => println!("Neither of the above patterns match x and y."), } print!("{} {}",x,y); }
これはなんとなくわかる。
ところがRustには「パターンにマッチするか」だけではなく、「マッチして、それが変数だったらそこに値を拘束する」という機能もある。
つまり以下は、
・「パターンマッチ」
・「value_of_yの変数宣言」
・「value_of_yへのyの代入」
が同時に行われている。
fn main() { let x:i32=5; let y:i32=7; // 「(5 , 10) というパターン」 match (x,y){ (5,10)=> println!("Both x and y are 5 and 10, respectively."), // パターンマッチングを行い、マッチした場合は値の拘束(変数の定義と代入)も行う (5,value_of_y )=> println!("x is 5, and y is {}",value_of_y), _ => println!("Neither of the above patterns match x and y."), } }
一事が万事この調子なので、変数を定義する機能だと思っていたletも、実はパターンマッチと、マッチした場合の値の拘束を同時に行う構文だということになる。
だからlet文で変数定義をするときに_ (ワイルドカード)が使えてしまう。
fn main() { // 例1 // (x,y)というパターンと(3,5)はマッチする // マッチするので、 // x に 3 を拘束 // y に 5 を拘束 // この二つを同時に行う。 let (x,y)=(3,5); // 例2 // (z,何でもいい) というパターンと (7,9) はマッチする // マッチするから 7 が z に 拘束される // _ はワイルドカードなので無視される。 let (z,_)=(7,9); println!("{} {} {} ",x,y,z); }
let文の=の右辺と左辺でパターンマッチを行い、拘束可能な部分は拘束する。拘束できないところは無視する。
こんなもの何に使うんだと思うのだが、ある構造体なりタプルかなりから値を取り出したい、しかし全部取り出す必要はないときに、不要な変数宣言を省略できるという利点がある。
fn main() { // 三つの三次元座標を用いて三角形を一枚定義 let triangle_points = [ (0,3,9), // 頂点1 (7,0,6), // 頂点2 (4,7,2) // 頂点3 ]; // この三角形を Z 平面に投影した二次元座標を取得したい for p in triangle_points{ // 三要素の p から前二つだけ取り出し、x,yに拘束 // 三つ目の要素は z に入れるべきだが、不要なので _ を指定して省略。つまり変数 z は定義しない。 let (x,y,_) = p; println!("{} {}",x,y); } }
Rust的には、「比較するものとされるものがマッチするならコンパイルが通る」わけで、当然構造体でも同じ理屈が通用する。
構造体の場合、無視の記号は .. を用いる。また構造体はフィールド名で値を選択するので、順番は気にしなくていい。
struct Point { x: i32, y: i32, z: i32, } fn main() { let point = Point { x: 0, y: 7, z: 9 }; // point からy座標だけ取り出したいので // y_coord変数を定義し、 point.y を拘束 // .. により、ほかのフィールドは無視する let Point { y:y_coord, .. } = point; // point.y が取れているか確認 println!("y value is {}",y_coord); }