自分用のScala書くときのメモ。
Optionの扱い方
一番詳しいページ:http://scalamanual.blog.fc2.com/blog-category-14.html
- OptionのNoneの処理は、 getOrElse で書ける。
- foldで、Noneの時のデフォルト値を設定できる。
以下3つ全部一緒の処理。この3つならmapでいいかと。
aOpt.map(_ > 10).getOrElse(true)
aOpt match {
case None => true
case Some(a) => a > 10
}
aOpt.fold(true){_ > 10}
パターンマッチを回避してOptionを処理する
Optionの値がSome(a)の時だけ続きの処理を行うにはmap, foreachを使う
val m = Map("A" -> "Apple", "B" -> "Banana")
val b = m.get("A").map{_.length} // 戻り値を使用
m.get("A").foreach{printf(_)} // 戻り値を返さない
boolean 値を帰す場合
boolean値を返す場合、existsやforall 等も使う事が出来る。 存在確認のcontainsもよく使う。
aOpt.exists(_ > 10)
aOpt.forall(_ > 10)
他、参照→ http://qiita.com/mizuki0420@github/items/ac7a6850aa3479ebc906
FlatMapの便利な使い方
1, mapにヒットしない時に、orElseを使って、後続の処理を書ける
val id = dog.map(_.id).getOrElse(cat.fold(None){_.id})
のようにOptionを返すような場合、flatMapを使うと、
val id = dog.flatMap(_.id).orElse(cat.flatMap(_.id))
とシンプルに書ける。
http://qiita.com/mtoyoshi/items/c95cc88de2910945c39d がちょう詳しい
複数のOptionがNoneじゃない時だけ処理する
val response = for {
i1 <- iOpt1
i2 <- iOpt2
} yield {
i1 + i2
}
のようにfor yieldを使うと良い。
実はこれ超便利で、mapとflatMapが入り乱れたものを完結に書くことが出来る。
i1.isDefined
が true
のときのみ、i2,i3...の処理が実行されるため、mapチェーンを完結に書くのに優れている。
例えば、以下の二式は同じ処理を行う。
people.flatMap(p =>
addresses.filter(a => p.addressId === a.id)
.map(a => (p.name, a.city))
).result
(for {
p <- people
a <- addresses if p.addressId === a.id
} yield (p.name, a.city)).result
例外処理
- Try match 文で Success Failureに分けて書く
Try(...) match {
case Success(a) => ...
case Failure(e) => ...
}
- Failureの処理だけしたい場合は、recoverを使うとエラーハンドリング処理だけシンプルに書ける。
Try(...).recover{ case e:Exception =>
log.error(e)
}
for の使い方
複数のTryの結果より正常処理とエラー処理を分ける場合はforを使うと良い。
http://tersesystems.com/2012/12/27/error-handling-in-scala/
val sum = for {
int1 <- Try(Integer.parseInt("one"))
int2 <- Try(Integer.parseInt("two"))
} yield {
int1 + int2
} recover {
case e => 0
}
可変長引数に展開する
Seq(...) : _* で展開できる
Mapのcaseの使い方
Mapをのkeyとvalueを反転したい時は、 case を使えば良い。
上のMapとkeyとvalueが反対になる。
private val AToBMap: Map[A, String] = BToAMap.map { case (key, value) => (value, key)}
PHPの var_dump()っぽいもの
import scala.runtime.ScalaRunTime._
println(stringOf( Array(1,2,3) )) // => Array(1, 2, 3)
Arrayではない適当なオブジェクトも、人が読める程度に出してくれた
Scala Collection Method
演算子系はこのページが一番詳しい
http://www.ne.jp/asahi/hishidama/home/tech/scala/collection/method.html
引数の事前チェック
if文でパラメータの引数チェックしてIllegalArgumentException 投げるくらいならrequireを使え。
- http://d.hatena.ne.jp/kaoskfos/20120401/p1
scala> def foo(a: Double, b: Double) = { require(b != 0); a / b }
foo: (a: Double, b: Double)Double
scala> foo(5, 2)
res0: Double = 2.5
scala> foo(4, 0) ←エラーになる
java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:145)
テスト関連
there was one で、引数を「a」に指定したいとき
there was one(mockClass).(===(a))
class A を継承して、Bをprotectedから外したいとき
TestA extends A {
override def B = super.B
}
型をテストしたいとき
beAnInstanceOfを使う
cat must beAnInstanceOf[Animal]