Rust 入門日記 (2) 型〜マクロ
実践 Rust プログラミング入門 を読んで気になったところをメモするシリーズ。
Result, Option
Option
: データが存在する場合、存在しない場合を表現する列挙型Result
: 処理の結果が成功かエラーかを表現する列挙型
Result のハンドリング
- パターンマッチ,
if let
が一般的 unwrap_or
,and_then
,?
演算子を使うと書き方が冗長にならずに便利- Result で回復可能なエラー - The Rust Programming Language 日本語版
- Rust のエラーハンドリングはシンタックスシュガーが豊富で完全に初見殺しなので自信を持って使えるように整理してみたら完全に理解した - Qiita
Box
- Rust の値は多くの場合、メモリのスタック領域に確保される
- 高速に扱うことが出来るが、コンパイル時にサイズが分かっており、固定サイズでなくてはいけない
- Box を使うと値はヒープ領域に確保される
- 確保したいタイミングで必要な文を確保する
- ヒープ領域に任意の型を格納し、スタック領域にヒープ領域へのポインタを置く
fn main() {
let byte_array = [b'h', b'e'];
print(Box::new(byte_array))
}
fn print(s: Box<[u8]>) {
println!("{:?}", s)
}
const と static
const
: コンパイラがビルドをする時に実際の値に置き換えられるstatic
: グローバルスコープで定義したstatic
の値はどこからでも変更ができてしまうため危険- 実行時に決まる定数を定義したい場合は
lazy_static
がおすすめ
- 実行時に決まる定数を定義したい場合は
match
- パターンマッチ
- match フロー制御演算子 - The Rust Programming Language 日本語版
- パターン記法 - The Rust Programming Language 日本語版
switch
みたいなもの- 列挙型で分岐する際には網羅性のチェックが行われる
fn main() {
let i: i32 = 2;
match i {
1 => println!("1"),
_ => println!("other"),
}
}
Iterator
for
ループはデータの集合から要素を取り出して繰り返し処理をすることができる- データの集合に Iterator トレイトが実装されているため
- 自作した型に Iterator トレイトを適用する例
fn main() {
let it = Iter {
current: 0,
max: 10,
};
for num in it {
println!("{}", num);
}
}
struct Iter {
current: usize,
max: usize,
}
impl Iterator for Iter {
type Item = usize;
fn next(&mut self) -> Option<usize> {
self.current += 1;
if self.current - 1 < self.max {
Some(self.current - 1)
} else {
None
}
}
}
impl
- 関数を構造体に紐づけておけば、オブジェクト指向のクラスのような扱いをすることができる
fn main() {
let p = Person {
name: String::from("Taro"),
age: 20,
};
p.say_name().say_age();
}
struct Person {
name: String,
age: u32,
}
impl Person {
fn say_name(&self) -> &Self {
println!("I am {}.", self.name);
self
}
fn say_age(&self) -> &Self {
println!("I am {} year(s) old.", self.age);
self
}
}
- 第一引数に
self
を使わなかった場合、関連関数の定義になる (?)- 関連関数: インスタンスからメソッドを呼ぶのではなく、型から関数を呼ぶ形式で定義される関数
- メソッド記法 - The Rust Programming Language 日本語版
fn main() {
let p = Person::new("Taro", 20);
p.say_name().say_age();
}
impl Person {
fn new(name: &str, age: u32) -> Person {
Person {
name: String::from(name),
age: age,
}
}
}
マクロ
- 関数のように扱えるマクロと、
#[derive]
アトリビュートによって実装を自動的に導出するマクロ- 定義の前の行に付与し、該当定義を拡張する
- マクロの呼び出しには
!
が付く - トレイトの導出 (derive) (?)
実装補助用のマクロ
いずれも実装が行われていない部分があっても型検査を通す
unimplemented!
: 未実装を示すtodo!
: 今後実装を示すunreachable
: match で条件を網羅していることを判定できない