LoginSignup
6
7

More than 5 years have passed since last update.

Scalaのガード

Last updated at Posted at 2017-11-06

Scalaのガード

近年においてガードが用いられるコードをよく見るようになりました。Scalaにおいてガードのモダンな書き方はどう書くのだろうと思ったので、纏めます。

ガードとは

ガードとは、処理の分岐においてtrueと評価し処理を継続させる条件を表す式であり、trueでなかった場合は別途例外処理を行うものです。
注意点として、関数の始まりのうちからパラメータに例外となりうる値が含まれている場合などにおいて、早めにreturnさせることでネストを減らすことができる早期リターンもまた、ガードを使いますが、ガード = 早期リターン ではありません。

scalaでガードを使う場合、シンプルに if と return の組み合わせで実現することが出来ます。

def hoo(bar: Int): Boolean = {
  if (bar < 0) return false
  true
}

hoo(-1)

ガードがある言語

ガードはif と returnで実現できますが、Swift等の言語には言語としてガードとしての機能があり、guardを用いて、不正な値の場合は、本来の処理を抜けて例外処理に移行することが出来ます。ここまでは通常のifでも可能ですが、Swiftの場合は、必ずreturnを書かなければコンパイルが通らないようになっています。また、String?は、オプショナル型なので、アンラップする必要がありますが、guard let でそのままアンラップの役割を果たすようになっています。

func hoo(bar: String?) {
    guard let baz = bar else {
        print("no string")
        return
    }
    print(baz)
}

hoo(bar: "string")
hoo(bar: nil)

パターンガード

if と return を使ったガードの他にガードの機能を有している式があります。

matchを使うパターンガード

def hoo(baz: Int) = baz match {
  case i: Int if i < 0 =>  false
  case _ => true
}

hoo(-1) // false
hoo(0)  // true
hoo(1)  // true

matchを使った場合は、上から順番に処理されていくため、パターンに応じてガードを書いていくことが可能で、ifとは異なり型のマッチングも簡潔に書くことができます。

for を使ったパターンガード

forのジェネレーターでifを使うことで、条件に当てはまらない場合は、for全体で None が返ります。
例はざっくりなので、Some(true) と None が返っているので getOrElse でbooleanに直しています。

def hoo(baz: Int) = {
  (for {
    _ <- Some(baz)
    if baz >= 0
  } yield {
    true
  }).getOrElse(false)
}

hoo(-1) // false
hoo(0)  // true
hoo(1)  // true

最後に

以上でScalaにおけるガードについて纏めた記事になります。Scalaでガードを使う場面は、scala.collection.Traversableのメソッドによって解決できることでもあるので、ガードを使うことがベストというわけではありません。
Scalaでガードはどうやるのかな?と疑問を解決するために纏めました。何かの解決になれば幸いです。

追記

scalamacrosを使いguard節を実装する例を書きました。
ScalaでRustっぽく書きたい 〜try!編〜

6
7
4

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
6
7