PartialFunction

specs2のAnyMatchers#beLikeを使ってみようと思ったらPartialFunctionなるものがでてきたので調べた

  /** matches if the value returns a successful result when applied to a PartialFunction */
  def beLike[T](pattern: PartialFunction[T, MatchResult[_]]) = new Matcher[T] {

PartialFuction(部分関数)ってなに?

まずDocs

www.scala-lang.org

概要

引数をひとつ取り、その引数が特定の値のときのみ結果を返却する関数

内部をみてみる

trait PartialFunction[-A, +B] extends (A => B) { self =>

まずFunction1を継承しているのがわかる
Function1は引数を1つとるごく普通の関数でたとえば

// こんなやつね
def hoge(arg: Int): Int = arg + 1

簡単な例をみながら

        val hoge = new PartialFunction[String, String] {
          def isDefinedAt(in: String): Boolean = in match {
            case "hoge" => true
            case _ => false
          }
          def apply(in: String): String = in match {
            case "hoge" => "hoge1"
          }
        }
  • PartialFunction[-A, +B] extends (A => B)に対してPartialFunction[String, String]なのでこれは、
    Stringを受け取り、Stringを返すFunction1を継承している

  • isDefinedAtっていうのが、引数が有効かどうか判定する関数でこいつがture返すものだけに結果を返却しfalseの場合はMatchErrorをはくようになっている。

実践

"hoge"が渡されれば、"hoge1"が返却され

        val hoge_1 = hoge("hoge")

hoge: PartialFunction[String,String] = <function1>
hoge_1: String = hoge1

"hogehoge"が渡されればMatchErrorが返る

        val hoge_2 = hoge("hogehoge")

scala.MatchError: hogehoge (of class java.lang.String)
  at $anon$1.apply(<console>:16)
  at $anon$1.apply(<console>:11)
  ... 36 elided

ひとまずParcialFunctionの概要はこんなかんじ

おまけ

syntaxsugar

{ case ... }がPartialFunctionのリテラルにないて簡単にかくことができる

scala> :paste
// Entering paste mode (ctrl-D to finish)

val hoge: PartialFunction[String, Int] = {case "1" => 1}

// Exiting paste mode, now interpreting.

hoge: PartialFunction[String,Int] = <function1>

ただ、型推論が聞かないらしく型の明示は必要っぽいね

scala> val hoge = {case "1" => 1}
<console>:11: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
       val hoge = {case "1" => 1}
                  ^

scala> val hoge: PartialFunction[String, Int] = {case "1" => 1}
hoge: PartialFunction[String,Int] = <function1>