🦀
Rustの勉強 6日目
The Rust Programming Language 日本語版 第6章
列挙型とパターンマッチについて
6.1 Enumを定義する
- 列挙型は
enum
キーワードで宣言する - 列挙型の列挙子は
型名::値名
で記述する
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
- 列挙子には直接データを格納することも可能。各列挙子で異なるデータ型を格納しても良い。
enum IpAddrKind {
V4(String),
V6(String),
}
let four = IpAddrKind(String::from("127.0.0.1"));
- Enumもメソッドが持てて構造体と同様に
impl
で実装する - Enumは直和型を実現する用途として使われている
-
Option
型はプレリュードにすら採用されている -
Option
型から値を取り出すためのメソッドがたくさん用意されている
-
6.2 match制御フロー演算子
- Enum型の列挙子に応じて処理をする場合にmatchが使える
- 列挙子が値を持っている場合には、変数をパターンに追加する
- これも OCaml とかのパターンマッチに似てる
enum Coin{
Penny,
Nickel,
Dime,
Quater(UsState),
}
fn value_in_cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => { // state で UsState の値を保持
println!("State quarter from {:?}!", state);
25
},
}
}
- Enum型をmatchするときはすべての列挙子に関してパターンを書かないといけない
- デフォルトのパターンを指定するために
_
というプレースホルダが使える。(これも OCaml に似てる)
- デフォルトのパターンを指定するために
6.3 if letで簡潔な制御フロー
-
if let
は特定のケースだけ処理したい場合のmatch
の糖衣構文のようなもの
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}", state);
} else {
count += 1
}
Rustlings
enums の一部がそれっぽいのでやってみる
enums1.rs
main
の中でアクセスされている型を定義して終わり
#[derive(Debug)]
enum Message {
Quit,
Echo,
Move,
ChangeColor,
}
fn main() {
println!("{:?}", Message::Quit);
println!("{:?}", Message::Echo);
println!("{:?}", Message::Move);
println!("{:?}", Message::ChangeColor);
}
enums2.rs
やはり enums1.rs
と同様に、 main
の messages
内で呼ばれているような値を持つように Message
の定義を埋めただけ。
#[derive(Debug)]
enum Message {
Move { x: i32, y: i32 },
Echo(String),
ChangeColor(i32, i32, i32),
Quit,
}
impl Message {
fn call(&self) {
println!("{:?}", &self);
}
}
fn main() {
let messages = [
Message::Move { x: 10, y: 30 },
Message::Echo(String::from("hello world")),
Message::ChangeColor(200, 255, 255),
Message::Quit,
];
for message in &messages {
message.call();
}
}
enums3.rs
テストで用意されていた処理と State
の定義をもとに Message
の列挙子の値の型を合わせたら終わった。
enum Message {
ChangeColor((u8, u8, u8)),
Echo(String),
Move(Point),
Quit,
}
struct Point {
x: u8,
y: u8,
}
struct State {
color: (u8, u8, u8),
position: Point,
quit: bool,
}
impl State {
fn change_color(&mut self, color: (u8, u8, u8)) {
self.color = color;
}
fn quit(&mut self) {
self.quit = true;
}
fn echo(&self, s: String) {
println!("{}", s);
}
fn move_position(&mut self, p: Point) {
self.position = p;
}
fn process(&mut self, message: Message) {
match message {
Message::ChangeColor(c) => self.change_color(c),
Message::Echo(s) => self.echo(s),
Message::Move(p) => self.move_position(p),
Message::Quit => self.quit(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_message_call() {
let mut state = State {
quit: false,
position: Point { x: 0, y: 0 },
color: (0, 0, 0),
};
state.process(Message::ChangeColor((255, 0, 255)));
state.process(Message::Echo(String::from("hello world")));
state.process(Message::Move(Point { x: 10, y: 15 }));
state.process(Message::Quit);
assert_eq!(state.color, (255, 0, 255));
assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15);
assert_eq!(state.quit, true);
}
}
Discussion