---
# System prepended metadata

title: Rust テキスト学習 3
tags: [struct, pattern, mut, Rust]

---

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

