Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Option型を使いこなして初心者から中級者へ / scala fukuoka
Search
KASUYA, Daisuke
May 28, 2016
Programming
4
5.1k
Option型を使いこなして初心者から中級者へ / scala fukuoka
Scala福岡発表資料
KASUYA, Daisuke
May 28, 2016
Tweet
Share
More Decks by KASUYA, Daisuke
See All by KASUYA, Daisuke
はてなの開発20年史と DevOpsの歩み / DevOpsDays Tokyo 2025 Keynote
daiksy
6
2.1k
わたしがEMとして入社した「最初の100日」の過ごし方 / EMConfJp2025
daiksy
16
8.5k
はてなのチーム開発一巡り / Hatena Engineer Seminar 30
daiksy
0
780
ふりかえりカンファレンスLT/Get Wild
daiksy
0
1.9k
スクラムマスターの採用事情 / scrum fest fukuoka 2023
daiksy
0
2.8k
スクラムのスケールとチームトポロジー / Scaled Scrum and Team Topologies
daiksy
1
1.4k
Scrum@Scaleの理論と実装 / RSGT2022
daiksy
2
10k
リモートワークに最適なスクラムチームの人数についての仮説 / Kyoto Agile 2021
daiksy
0
270
スクラムを軸に据えた キャリア戦略 / Scrum Fest Osaka 2021
daiksy
2
7.1k
Other Decks in Programming
See All in Programming
What's new in Adaptive Android development
fornewid
0
130
Comparing decimals in Swift Testing
417_72ki
0
160
SQLアンチパターン第2版 データベースプログラミングで陥りがちな失敗とその対策 / Intro to SQL Antipatterns 2nd
twada
PRO
36
11k
Bedrock AgentCore ObservabilityによるAIエージェントの運用
licux
8
560
MySQL9でベクトルカラム登場!PHP×AWSでのAI/類似検索はこう変わる
suguruooki
1
280
0から始めるモジュラーモノリス-クリーンなモノリスを目指して
sushi0120
0
250
抽象化という思考のツール - 理解と活用 - / Abstraction-as-a-Tool-for-Thinking
shin1x1
1
930
書き捨てではなく継続開発可能なコードをAIコーディングエージェントで書くために意識していること
shuyakinjo
0
200
AWS Summit Japan 2024と2025の比較/はじめてのKiro、今あなたは岐路に立つ
satoshi256kbyte
1
260
React は次の10年を生き残れるか:3つのトレンドから考える
oukayuka
41
16k
Gemini CLIの"強み"を知る! Gemini CLIとClaude Codeを比較してみた!
kotahisafuru
3
920
一人でAIプロダクトを作るならAIにはもっと働いてもらいたい / I want AI to work harder
rkaga
3
320
Featured
See All Featured
Large-scale JavaScript Application Architecture
addyosmani
512
110k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
110
19k
Facilitating Awesome Meetings
lara
54
6.5k
GraphQLとの向き合い方2022年版
quramy
49
14k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
2.9k
Code Review Best Practice
trishagee
69
19k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.9k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.5k
Statistics for Hackers
jakevdp
799
220k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
1k
Transcript
0QUJPOܕΛ͍͜ͳ͠ ͯॳ৺ऀ͔Βதڃऀ 4DBMBԬ
ࣗݾհ • 粕谷 大輔 • id:daiksy • @daiksy • 株式会社
はてな • Mackerel開発チーム • Mackerelのニュースレターと 告知ブログの中の人です
None
None
None
Scala教科書(基礎)の目次 (講義時間約2時間) • 参考文献 • 開発環境 & Hello World •
varとvalとif式 • パターンマッチ • コレクション • Option型 • for式 • クラス定義 (case class, object, trait など) • implicit conversion/parameter • 型パラメータ • オブジェクト指向と関数プログラミング
Scala教科書(基礎)の目次 (講義時間約2時間) • 参考文献 • 開発環境 & Hello World •
varとvalとif式 • パターンマッチ • コレクション • Option型 • for式 • クラス定義 (case class, object, trait など) • implicit conversion/parameter • 型パラメータ • オブジェクト指向と関数プログラミング
Option型 • nullの不便さからの卒業 (さらばヌルポ) • 値が存在しないかもしれない、という文脈を表 現 (Some or None)
val o: Option[String] = Some("Hello") o: Option[String] = Some(Hello) val
o: Option[String] = None o: Option[String] = None val o: Option[String] = Option(null) o: Option[String] = None
val m = Map("key" -> "value") m: scala.collection.immutable.Map[String,String] = Map(key
-> value) m.get("key") Option[String] = Some(value) m.get("hoge") Option[String] = None
Option型 • undefチェックが型によって強制される
o.replace("Hello", "Hello World") <console>:12: error: value replace is not a
member of Option[String] o.replace("Hello", "Hello World") ^ if (o.isDefined) { o.get.replace("Hello", "Hello World") }
Option型の値への アクセス • get • getOrElse • match式
val o = Some("Hello") o: Some[String] = Some(Hello) o.get String
= Hello val o = None o: None.type = None o.get java.util.NoSuchElementException: None.get at scala.None$.get(Option.scala:347) ... 32 elided
val o = Some("Hello") o: Some[String] = Some(Hello) o.getOrElse("undefined") res4:
String = Hello val o = None o: None.type = None o.getOrElse("undefined") res5: String = undefined
val o: Option[String] = Some("Hello") o: Option[String] = Some(Hello) o
match { case Some(s) => s case None => "undefined" } res1: String = Hello
Option型の計算 • Optionは「値がない可能性」を文脈に持つ型 • Optionからいちいち値を取り出す必要はない • Option型のまま扱おう
Option型の計算 • 例1) Option[Int] と Intの計算
val o: Option[Int] val i: Int o.map(_ * i) o
が Some(5), i が 2の場合 => Some(10) o が None, i が 2の場合 => None
Option型の計算 • 例2) Option[Int] と Option[Int]の計算
val option1: Option[Int] val option2: Option[Int] option1.flatMap{ o1 => option2.map{
o2 => o1 * o2 } } いずれかの値がNoneの場合 => None 両方値がある場合 => Some(o1 * o2)
Option型の計算 • 例3) Option[Int]が3つの時の計算
val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] option1.flatMap{
o1 => option2.flatMap{ o2 => option3.map{ o3 => o1 * o2 * o3 } }
val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val
option4: Option[Int] option1.flatMap{ o1 => option2.flatMap{ o2 => option3.flatMap{ o3 => option4.map{ o4 => o1 * o2 * o3 * 04 } } }
Option型の計算 • ネスト深すぎてつらい… • しかしつらくない書き方がある • その前に少し寄り道
for式
for式 • ループの制御構文 • Scalaのforはめっちゃ高機能
for ( i <- (1 to 10) ) { println(i)
} val list = List(1, 2, 3, 4, 5) for ( i <- list) { println(i) } コレクションの要素をひとつずつ取り出して繰り返す
for ( i <- (1 to 10) if ( i
% 2 == 0) ) { println(i) } ループ要素に対して if で条件を指定できる
for ( i <- (1 to 10)) yield i *
2 => Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) for式自体が値をかえすことができる
for { i <- (1 to 10) j <- (1
to 10) } yield i * j forの入れ子はネストせずにフラットに書ける
for式 • これらのfor式は、実はコレクションのメソッド が呼ばれている
for ( i <- (1 to 10) ) { println(i)
} (1 to 10).foreach ( println(_) )
for ( i <- (1 to 10) if ( i
% 2 == 0) ) { println(i) } (1 to 10).filter( _ % 2 == 0).foreach( println(_) )
for ( i <- (1 to 10)) yield i *
2 => Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) (1 to 10).map( _ * 2)
for { i <- (1 to 10) j <- (1
to 10) } yield i * j (1 to 10).flatMap{ i => (1 to 10).map{ j => i * j } }
foreach, withFilter(filter), flatMap(map) これらのメソッドが実装されているコレクションは for式に置き換えることができる
for式はコレクションに対するマクロのようなもの for式は内部的にforeachなどの呼び出しに変換される
以下のようにREPLを起動してみよう $ scala -Xprint:parser
scala> for (i <- 0 to 1) yield i +
1 (中略) val res0 = 0.to(1).map(((i) => i.$plus(1))) (中略) scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)
for式はコンパイル時にコレクションのメソッド呼び出しに 変換される。 型チェックの前に変換されるので、for式内で使われている 値の型は関係ない(式展開後に型チェックが走る) 変換ルールは対象の値に変換可能なメソッドが実装されて いるかどうか
変換ルールは4種類
1. mapを定義している型では 1個のジェネレータで構成されたfor式を使える list.map(i => i * 2) for {
i <- list } yield i * 2
2. mapの他にflatMapも定義している型では、複数のジェネ レータから構成されるfor式を使える list.flatMap{ i => list2.map { j =>
i * j } } for { i <- list j <- list2 } yield i * j
3. foreachを定義している型では、forループを使える (ジェネレータは1個でも複数でもよい) list.foreach { i => list2.foreach { j
=> println(i + j) } } for { i <- list j <- list2 } { println(i * j) }
4. withFilterを定義している型では、for式の中でifで始 まるフィルター式を使える list.withFilter(_ % 2 == 0).flatMap { i
=> list2.map { j => i * j } } for { i <- list if i % 2 == 0 j <- list2 } yield i * j
自分で実装してみよう
case class Custom(v: String) { def foreach(f: String => Unit):
Unit = f(v) } for { c <- Custom("Fukuoka") } println(s“Hello $c”)
応用編: for式にパターンマッチが含まれる場合
val xs = List( Seq(1, 2), Seq(1, 2, 3), Seq(1,
2, 3, 4) ) for { Seq(x, y, z) <- xs } yield x + y + z
単純に下のように変換してしまうと実行時に MatchErrorが発生してしまう for { Seq(x, y, z) <- xs }
yield x + y + z xs.map { case Seq(x, y, z) => x + y + z } しかし、上のfor式はエラーにならない。なぜか。
この場合はmapに加えてwithFilterが式展開される for { Seq(x, y, z) <- xs } yield
x + y + z xs.withFilter { case Seq(x, y, z) => true case _ => false }.map { case Seq(x, y, z) => x + y + z } なのでmatchしないパターンは読み飛ばされる
Optionに話を戻そう
Optionに実装されているメソッド asInstanceOf flatMap isDefined orNull toRight canEqual flatten isEmpty productArity
toString collect fold isInstanceOf productElement withFilter contains forall iterator productIterator exists foreach map productPrefix filter get nonEmpty toLeft filterNot getOrElse orElse toList
Option型 => 要素数が0または1のコレクション
Option型 => 要素数が0または1のコレクション => for式に置き換え可能
val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val
option4: Option[Int] option1.flatMap{ o1 => option2.flatMap{ o2 => option3.flatMap{ o3 => option4.map{ o4 => o1 * o2 * o3 * 04 } } }
val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val
option4: Option[Int] for { o1 <- option1 o2 <- option2 o3 <- option3 o4 <- option4 } yield o1 * o2 * o3 * o4 スッキリ!!!!!!
Optionやコレクション以外でforを使う例
val usdQuote = Future { connection.getCurrentValue(USD) } val jpyQuote =
Future { connection.getCurrentValue(JPY) } val purchase = for { usd <- usdQuote jpy <- jpyQuote if isProfitable(usd, jpy) } yield connection.buy(amount, jpy) purchase onSuccess { case _ => println("OK") } USDとJPY両方の connection.getCurrentValue が完了したタイミ ングで connection.buy が実行される 非同期処理
val item1: Either[Error, Item] = validationItem1 val item2: Either[Error, Item]
= validationItem2 for { i1 <- item1.right i2 <- item2.right } insertData(i1, i2) いずれかがLeft(Error)の場合、このfor式はLeft(Error)を かえす validation
for式を使いこなすと Scala中級者!!!
We are Hiring!! 東京 or 京都でエンジニア絶賛募集中 学生さんはインターンへのご応募ぜひ!!
͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠