LoginSignup
76

More than 5 years have passed since last update.

Scalaの綺麗な書き方(メモ用)

Last updated at Posted at 2015-10-05

自分用の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.isDefinedtrue のときのみ、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]

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76