<style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.5; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #AAA; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #2980b9;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #AAA;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #CCC;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.5vw 6.0vw; font-style: italic; background: #f5f5f5; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #2980b9; font-size: 3.0vw; } /* font size */ .reveal h1 {font-size: 4.0vw;} .reveal h2 {font-size: 3.5vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.0vw;} .reveal code {font-size: 1.0vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.0vw #2980b9; border-bottom: solid 0.6vw #d7d7d7; } </style> <!-- --------------------------------------------------------------------------------------- --> # Rust Study Session \#18 ## Ch.18 - パターンとマッチング ### 2020.12.18 - horikawa ###### tags: `Rust` --- ## よろしくおねがいします * 一週遅れてすみませんでした:bow: * 今日は[18章パターンとマッチング](https://doc.rust-jp.rs/book/second-edition/ch18-00-patterns.html)をやります * `match`は6章で軽くやりました。今回は、より深くやる回です * パターンはmatchでの左辺 * match ≠ マッチング * >パターンは、複雑であれ、単純であれ、Rustで型の構造に一致する特別な記法です。 ---- ## パターンとマッチング 本題. パターンは値の構造に合致する * パターンが使用されることのある箇所全部 * 論駁可能性: パターンが合致しないかどうか * パターン記法 --- ## パターンが使用されることのある箇所全部 * リテラル * 分配された配列、enum、構造体、タプル * 変数 * ワイルドカード * プレースホルダー ---- ### match アーム ```rust= match VALUE { PATTERN => EXPRESSION, PATTERN => EXPRESSION, PATTERN => EXPRESSION, } ``` * 全体が`match`式 * それぞれの`PATTERN => EXPRESSION`がアーム * `PATTERN`がパターン ---- ### if 条件分岐 ```rust= fn main() { let favorite_color: Option<&str> = None; let is_tuesday = false; let age: Result<u8, _> = "34".parse(); if let Some(color) = favorite_color { println!("Using your favorite color, {}, as the background", color); } else if is_tuesday { println!("Tuesday is green day!"); } else if let Ok(age) = age { if age > 30 { println!("Using purple as the background color"); } else { println!("Using orange as the background color"); } } else { println!("Using blue as the background color"); } } ``` * `if let PATTERN=hoge {}`の形式 ---- ### while ループ ```rust= #![allow(unused_variables)] fn main() { let mut stack = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("{}", top); } } ``` * `while let PATTERN`の形式 ---- ### for ループ ```rust= #![allow(unused_variables)] fn main() { let v = vec!['a', 'b', 'c']; for (index, value) in v.iter().enumerate() { println!("{} is at index {}", value, index); } } ``` * `for PATTERN in ..`の形式 ---- ### let 文 ```rust= let x = 5; ``` は ```rust= let PATTERN = EXPRESSION; ``` に対応したパターンらしい >このパターンは実質的に「値が何であれ、全てを変数xに束縛しろ」を意味します。 ```rust= let (x, y, z) = (1, 2, 3); ``` とかもパターン 他の言語と違って括弧()は必須 ---- ### 関数の引数 ```rust= fn foo(x: i32) { // code goes here } ``` ```rust= fn print_coordinates(&(x, y): &(i32, i32)) { println!("Current location: ({}, {})", x, y); } fn main() { let point = (3, 5); print_coordinates(&point); } ``` * `fn hoge(PATTERN){}`の形式 --- ## 論駁可能性 * 論駁可能性 * 論駁: 相手の説に反対して、論じ攻撃すること。 * 他の資料探したけど同様の表現見当たらず.. * 英語: Refutability * 反証可能性 * 論駁可能性で何が変わる? * 使える構文の形が変わる ---- ### 例 * 論駁不可能の例 * `let x = 5;`での`x` * 論駁可能 * `if let Some(x) = a_value`での`Some(x)` ---- ### もう少し例 (論駁不可能) * OK * `let x = 5` * NG * `if let x = a_value{ .. }` * 他の論駁不可能な例 * `(a,b)`: タプル ---- ### もう少し例 (論駁可能) * NG * `let Some(x) = 5` * OK * `if let Some(x) = a_value{ .. }` * 他の論駁不可能な例 * `Some`の周辺以外は存在しない? ---- ### もう少し例 (if let) これが ```rust= let some_u8_value = Some(0u8); match some_u8_value { Some(3) => println!("three"), _ => (), } ``` ---- ### もう少し例 (if let) こう書ける ```rust= let some_u8_value = Some(0u8); if let Some(3) = some_u8_value { println!("three"); } ``` https://doc.rust-jp.rs/book-ja/ch06-03-if-let.html >if letを使うと、タイプ数が減り、インデントも少なくなり、定型コードも減ります。しかしながら、 matchでは強制された包括性チェックを失ってしまいます。matchかif letかの選択は、 特定の場面でどんなことをしたいかと簡潔性を得ることが包括性チェックを失うのに適切な代償となるかによります。 --- ## パターン記法 ### リテラルにマッチする ```rust= let x = 1; match x { 1 => println!("one"), // 1 2 => println!("two"), // 2 3 => println!("three"), // 3 _ => println!("anything"), // なんでも } ``` ---- ### 名前付き変数にマッチする ```rust= fn main() { let x = Some(5); let y = 10; match x { Some(50) => println!("Got 50"), Some(y) => println!("Matched, y = {:?}", y), _ => println!("Default case, x = {:?}", x), } println!("at the end: x = {:?}, y = {:?}", x, y); } ``` ---- ### 複数のパターン ```rust= let x = 1; match x { 1 | 2 => println!("one or two"), 3 => println!("three"), _ => println!("anything"), } ``` ---- ### ...で値の範囲に合致させる ```rust= let x = 5; match x { 1 ... 5 => println!("one through five"), _ => println!("something else"), } ``` * `1...5`は1から4にmatchする * `1 | 2 | 3 | 4` でも同じ * `1...=4`でも同じ ---- ### 構造体を分解する ```rust= struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; let Point { x: a, y: b } = p; assert_eq!(0, a); assert_eq!(7, b); } ``` ---- ### enumを分配する ```rust= enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), } fn main() { let msg = Message::ChangeColor(0, 160, 255); match msg { Message::Quit => { // Quit列挙子には分配すべきデータがない println!("The Quit variant has no data to destructure.") }, Message::Move { x, y } => { println!( // x方向に{}、y方向に{}だけ動く "Move in the x direction {} and in the y direction {}", x, y ); } // テキストメッセージ: {} Message::Write(text) => println!("Text message: {}", text), Message::ChangeColor(r, g, b) => { println!( // 色を赤{}, 緑{}, 青{}に変更 "Change the color to red {}, green {}, and blue {}", r, g, b ) } } } ``` ---- ### 参照を分配する ```rust= let points = vec![ Point { x: 0, y: 0 }, Point { x: 1, y: 5 }, Point { x: 10, y: -3 }, ]; let sum_of_squares: i32 = points .iter() .map(|&Point { x, y }| x * x + y * y) .sum(); ``` ---- ### 構造体とタプルを分配する ```rust= let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 }); ``` 気が利くなあ ---- ### `_`で値全体を無視する ```rust= fn foo(_: i32, y: i32) { println!("This code only uses the y parameter: {}", y); } fn main() { foo(3, 4); } ``` >トレイトを実装する際、 特定の型シグニチャが必要だけれども、自分の実装の関数本体では引数の1つが必要ない時など > そうすれば、代わりに名前を使った場合のようには、未使用関数引数についてコンパイラが警告することはないでしょう。 ---- ### ネストされた`_`で値の一部を無視する ```rust= let mut setting_value = Some(5); let new_setting_value = Some(10); match (setting_value, new_setting_value) { (Some(_), Some(_)) => { // 既存の値の変更を上書きできません println!("Can't overwrite an existing customized value"); } _ => { setting_value = new_setting_value; } } ``` >2番目のアームの_パターンで表現される他のあらゆる場合(setting_valueとnew_setting_valueどちらかがNoneなら)には、 new_setting_valueにsetting_valueになってほしいです。 ---- ### 名前を`_`で始めて未使用変数を無視する ```rust= fn main() { let _x = 5; let y = 10; } ``` * yについてのみ未使用の警告 ---- ### コンパイルエラーになる例 ```rust= let s = Some(String::from("Hello!")); if let Some(_s) = s { println!("found a string"); } println!("{:?}", s); ``` 解決するには: ```rust= let s = Some(String::from("Hello!")); if let Some(_) = s { println!("found a string"); } println!("{:?}", s); ``` ---- ### `..`で値の残りの部分を無視する ```rust= struct Point { x: i32, y: i32, z: i32, } let origin = Point { x: 0, y: 0, z: 0 }; match origin { Point { x, .. } => println!("x is {}", x), } ``` * 気が利くので`Point { .., x, .. }`とかはエラーになります ---- ### refとref mutでパターンに参照を生成する ```rust= let robot_name = Some(String::from("Bors")); match robot_name { Some(name) => println!("Found a name: {}", name), None => (), } println!("robot_name is: {:?}", robot_name); ``` * ↑これはエラー * 所有権を奪わせずに借用する↓ ```rust= let robot_name = Some(String::from("Bors")); match robot_name { Some(ref name) => println!("Found a name: {}", name), None => (), } println!("robot_name is: {:?}", robot_name); ``` * `&`が使えないので`ref`をつかう * [Rustの"&"と"ref"の違い](https://qiita.com/terakoya76/items/cb5c1212e20fb98cb10e) * ref mutを使用して、パターンの一部として値への可変参照を生成することもできます ---- ### マッチガードで追加の条件式 (1) ```rust= let num = Some(4); match num { // 5未満です: {} Some(x) if x < 5 => println!("less than five: {}", x), Some(x) => println!("{}", x), None => (), } ``` ---- ### マッチガードで追加の条件式 (2) ```rust= fn main() { let x = Some(5); let y = 10; match x { Some(50) => println!("Got 50"), Some(n) if n == y => println!("Matched, n = {:?}", n), _ => println!("Default case, x = {:?}", x), } println!("at the end: x = {:?}, y = {:?}", x, y); } ``` ---- ### マッチガードで追加の条件式 (3) ```rust= let x = 4; let y = false; match x { 4 | 5 | 6 if y => println!("yes"), _ => println!("no"), } ``` * `(4 | 5 | 6) if y`であって`4 | 5 | (6 if y)`でない ---- ### `@`束縛 ```rust= enum Message { Hello { id: i32 }, } let msg = Message::Hello { id: 5 }; match msg { Message::Hello { id: id_variable @ 3...7 } => { println!("Found an id in range: {}", id_variable) }, Message::Hello { id: 10...12 } => { println!("Found an id in another range") }, Message::Hello { id } => { println!("Found some other id: {}", id) }, } ``` * 値を保持する変数の生成と同時に、その値のパターン一致を調べることが可能 --- ## まとめ * Rustのパターンはmatchだけでなく、letやfunなどでも使われる * matchは網羅性を保証するので便利 *
{"metaMigratedAt":"2023-06-15T17:04:01.927Z","metaMigratedFrom":"YAML","title":"Rust Ch.18","breaks":true,"description":"Rust Ch.18","slideOptions":"{\"theme\":\"black\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"fade\",\"keyboard\":true}","contributors":"[{\"id\":\"41421433-16a1-4a57-ac11-6f7b7becb765\",\"add\":13640,\"del\":1840}]"}
    169 views