Rust勉強メモ/列挙型とパターン
?ヴァリアントのインポート
「プログラミングRust 第2版」p.208
code:Rust
use std::cmp::Ordering::{self, *}; // * to import all children
fn compare(n: i32, m: i32) -> Ordering {
if n < m {
Less
} else if n > m {
Greater
} else {
Equal
}
}
selfの意味、役割は?
Ordering型そのものをインポートする際は use std::cmp::Ordering;で、selfは登場しない
Orderingを使えるようにするための記述か?
code:Rust
use std::cmp::Ordering::{self, *};
// 上1行と、下2行は等価?
use std::cmp::Ordering;
use std::cmp::Ordering::*;
列挙型の整数サイズをreprで制御
「プログラミングRust 第2版」p.609
code:Rust
enum git_error_code {
GIT_OK = 0,
GIT_ERROR = -1,
...
}
列挙型のメモリ表現がCのintサイズとなる
code:Rust
enum git_error_code {
16ビット整数となる
?比較演算子などの自動定義
「プログラミングRust 第2版」p.210
code:Rust
enum TimeUnit {
Copyは、代入時に移動ではなくコピーをするトレイトか
Debugはprintできるようにするやつ?
PartialEqは何者?
データを保持するヴァリアント
「プログラミングRust 第2版」p.211
タプル型ヴァリアントと構造体型ヴァリアントを混ぜて使える
code:Rust
enum RelationshipStatus {
Single,
InARelationship,
ItsComplicated(Option<String>),
ItsExtremelyComplicated {
car: DifferentialEquation,
cdr: EarlyModernistPoem,
},
}
列挙型のメモリ表現
「プログラミングRust 第2版」p.211
小さい整数のタグと最大のヴァリアントのすべてのフィールドを保持するのに十分なサイズのメモリで構成される
Rustで書いたデータ付き列挙型
code:Rust
enum RoughTime {
InThePast(TimeUnit, u32),
JustNow,
InTheFuture(TimeUnit, u32),
}
Cで書くと以下の構造体のような感じ
code:C
struct RoughTime {
enum {
InThePast, JustNow, InTheFuture
} tag;
union {
TimeUnit unit;
uint32_t time;
} value;
};
ただし、Rustではtagは1バイトになる
将来的にはもっと違うメモリ表現になる可能性がある。コンパイラの最適化しだい。
?0を値に取らない型とOption
「プログラミングRust 第2版」p.214
Option<T>のTに、0を値として取らない型を渡すと、全体として1ワードで表現できる
0をNone、非0をSome
必ずそうなる?それとも、たまたまコンパイラが頑張ってそうした?
参照やBoxなどのスマートポインタ
std::num::NonZeroUsize
定義が気になって見てみたらマクロによる魔術だった
?ジェネリック列挙型を用いたバイナリツリー
「プログラミングRust 第2版」p.214
code:Rust
enum BinaryTree<T> {
Empty,
NonEmpty(Box<TreeNode<T>>),
}
struct TreeNode<T> {
element: T,
left: BinaryTree<T>,
right: BinaryTree<T>,
}
なぜ2つの型に分けた?
素朴に定義するならTreeNode<T>が自己参照する定義になりそうだが
code:Rust
struct TreeNode<T> {
element: T,
left: Box<TreeNode<T>>,
right: Box<TreeNode<T>>,
}
Box単体では、Null値を表せない?
BinaryTreeは単に「Nullを表せるスマートポインタBox」という感じ?
?Boxか参照か
どこにBoxを置くべきなのかがわからないのではないだろうか。
そして、図から逆にコードを書くのだ。長方形は構造体かタプルで実装し、矢印はBoxなどのスマートポインタになる。
「プログラミングRust 第2版」p.216
Boxの代わりに参照&を検討することに価値はあるのか?
開区間によるパターンマッチは実験的機能
半開区間(..)をパターンマッチで使ってみた
code:Rust
fn range_match(val: u64) -> u64 {
match val {
0..4 => 1,
6..=10 => 2,
_ => 0,
}
}
エラーらしい
code:Text
errorE0658: exclusive range pattern syntax is experimental --> src/main.rs:49:9
|
49 | 0..4 => 1,
| ^^^^
?パターンの型
「プログラミングRust 第2版」p.218
ref変数と参照の違いは?
ref field, ref mut field
&value, &(k, v)
?参照パターンのマッチ
code:Rust
struct Engine {
num_cylinder: u64
}
struct Car {
engine: Engine
}
fn ref_pattern() {
let car = Car{ engine: Engine{ num_cylinder: 2 }};
assert_eq!(1, match &car {
Car { engine } => 1,
&Car { engine } => 2,
_ => 0,
});
}
https://gyazo.com/17c72a1044537072dae30b93f16f13b8
Car { engine } の行が同様のエラーにならないのはなぜ?
Orパターン
'a' | 'A'
Some("left" | "right")
反駁可能パターンでしか使えない(match, if let, while let)
「プログラミングRust 第2版」p.219
反駁可能パターンとは?
反駁可能パターン(refutable pattern)はマッチしないかもしれないパターンだ。
「プログラミングRust 第2版」p.227
反駁不能パターン
パターンPoint3d { x, y, z }は、すべてのPoint3d構造体にマッチする。(x, y)は、すべての(f64, f64)ペアにマッチする。Rustにおいては、常にマッチするパターンは特別だ。これらは反駁不能パターン(irrefutable patterns)と呼ばれる。
「プログラミングRust 第2版」p.226
match, if let, while let では「マッチしなかった場合」というのを考えられるが、単なるletでは「マッチしなかった場合」は存在できない