###### 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なのでパターンにマッチせず _ にマッチする。