###### tags: `Rust` `mut` `struct` `pattern` `mut` # Rust テキスト学習 3 [TOC] # mutability mutablity = 変更する能力 Rustは変数がデフォルトでは変更できない。 **mut** キーワードで変更できるようになる。 ```rust= let mut x = 5; let mut y = &mut x; ``` **mut** はパターンの一部をなす。 下記のような使い方ができる ```rust= let (mut x, y) = (5, 6); // 関数の引数すべてをmutにする fn foo (mut x: i32, y: i32){...} ``` ## 内側のmutable & 外側のimutable ```rust= use std::sync::Arc; let x = Arc::new(5); let y = x.clone(); ``` Arc\<T>.clone() を実行すると、参照カウントが増える。 つまり、変数が変更されるわけだが、 x は mut ではない。 これは、x.clone() が実行されるArc構造体の内側のmutなメンバーが変更されているので問題ない。 外側からは見えないが。 ## 構造体のフィールドレベルのmutability mutabilityは借用と束縛に関する属性。 一部がミュータブル、一部はイミュータブルといったstructは作れない。 ただし、 Cell\<T> ジェネリックオブジェクトを使うと、 ルールを無視してフィールドレベルのミュータビリティを実装できる。 ```rust= struct Vertex { x: i32, y: mut i32, //だめ } use std::Cell::Cell; struct Point { x: i32, y: Cell<i32>, // OK } ``` Cell\<T>で実装されたメンバを変更するときは、Cell.set()メソッドを使う ```rust= let p = Point {x: 5, y: 6 }; p.y.set(7); ``` # 構造体 struct ```rust= struct Point{ x: i32, y: i32, } // 初期化はkey value スタイルで let p = Point {x: 5, y: 7}; ``` ## 構造体のアップデート構文 デフォルトでは、構造体のフィールドレベルのmutは機能しない。 しかし、 mut な変数束縛は、別の構造体を束縛することができる。 すなわち、新しい構造体を作って束縛することで、変更とできる。 アップデート構文を使うことで、元の構造体をコピーしつつ指定したフィールドを更新できる。 また、他の構造体束縛を使うこともできる。 ```rust= let origin = Point{x: 0, y: 0, z: 0}; let new_pos = Point{y: 10, .. origin}; ``` ## タプル構造体 ```rust= struct Color(i32, i32, i32); struct Point(i32, i32); ``` 多くの場合は、普通の構造体を使ったほうがいい。 構造体は、名前をつけられたデータの集まりであることが重要であるため。 例外として、1つしか値を持たないタプル構造体を作る場合で、 newtypeパターンと呼ばれる ## Unit-like Struct Unitとは = () からのタプルをそう呼ぶ ```rust= struct Electron; ``` フィールドを何も持たない構造体のこと 単体では難の役にも立たない # match if else では十分ではない分岐条件を処理する スイッチ文の代わり matchという単語はパターンマッチに由来する。 ```rust= match x { val => expression, val => expression, ... _ => default_expression, } ``` valの部分はパターンであり、いろいろな表現で書ける。 ### _ switch文のdefaultの代わり どのパターンにもマッチしに場合、アンダースコアの腕で処理される。 ### 列挙型マッチ 重要な利用法として、列挙型のバリアントのマッチがある 列挙型を用いた分岐にはifを用いることができない match か if let でのみ処理できる。 # パターン ### パターンの落とし穴 ```rust= let x = 'x'; let c = 'c'; match c { x => println!("x: {} c: {}", x, c), } println!("x: {}", x) ``` 単なるxをパターンに置くと、xの変数束縛がシャドーイングされ 中身が`c`になる ## 複式パターン or記号 | を使って複数パターンにマッチさせる ```rust= match x { 1 | 2 => println!("one or two"), } ``` ## 分配束縛 structのような複合データ型をパターン内で分解して別々の変数に代入させる。 コロン : を使って別名もつけられる ES6の分割代入のイメージ ```rust= struct Point { x: i32, y: i32, } let origin = Point { x: 0, y: 0 }; match origin { Point { x, y } => println!("({},{})", x, y), } ``` 分配束縛は、 - tuple - enum - struct で利用できる。 ## 束縛無視 _ パターン内の値を無視する Result<T, E> 型に対してmatchしてみる ```rust= match some_value { Ok(value) => println!("got a value: {}", value), Err(_) => println!("an error occurred"), } ``` これは、要素1のタプル列挙型の分配束縛である Err(_) で、Err 型の中身を無視して、一般的なエラーを表示する。 match 式以外でも、関数の戻り値で3要素のタプルが帰ってくる場合など 使わない要素を _ で受けて捨てることもできる。 これは、Golangなどでもよくあった手法 ```rust= fn coordinate() -> (i32, i32, i32) { // 3要素のタプルを生成して返す } let (x, _, z) = coordinate(); // 複数値を無視するには .. を使う let (x, ..) = cordinate(); ``` ## ref キーワード パターンで参照を取得するためのキーワード ```rust= let x = 5; match x { ref r => println!("{}", r); } ``` `ref 変数名` : 変数名にマッチさせて、参照を束縛して右の式で使用できる。 ### 1 ... 5 範囲マッチ start ... end で値を範囲マッチさせる。 主に、 int か char で使われる。 ```rust= match x { 1 ... 5 => println!("1から5の間"), 'a' ... 'z' => println("小文字のアルファベット"), } ``` 1 ... 5 は 1|2|3|4|5 のパターンと等価 ### 名前 @ パターン パターンにマッチしたものを名前に束縛する @ と | を併用するときは、 区切られた名前@パターンそれぞれに 同じ名前が束縛されるように書く ```rust= match x { e @ 1 ... 5 => println!("got a range element {}", e), e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e), _ => println!("anything"), } ``` ### マッチガード パターン if condition で、マッチするかどうかを制御する conditionがtrueならマッチ、falseならマッチしない ```rust= let x = 4; let y = false; match x { 4 | 5 if y => println!("yes"), _ => println!("no"), } ``` 上のパターンはyがfalseなのでパターンにマッチせず _ にマッチする。