14

部分関数

Scala では、aPartialFunctionは要するに、isDefinedAtメソッドを追加で定義する関数です。

一連のcaseステートメントで部分関数を定義するのは簡単です。些細な例は、たとえば次のようになります。

scala> val pf: PartialFunction[Int, Unit] = {
     | case 42 => ()
     | }
pf: PartialFunction[Int,Unit] = <function1>

scala> pf.isDefinedAt(42)
res0: Boolean = true

scala> pf.isDefinedAt(0) 
res1: Boolean = false

isDefinedAtcase部分関数を定義する のリストから自動的に生成されます。

環境

Lift フレームワークは、リクエストを Lift のエンジンで処理するか、ディスク上のファイルからそのまま処理するかを定義するなど、多くの場所で部分関数を使用します。また、caseすべての入力パラメーターに一致するステートメントを作成し、値を返すかどうかを後で決定したいと思うこともあります。これは、最初の一連のcases では、関数が特定の値で定義されているかどうかを判断するのに十分ではないことを意味します

たとえば、Lift では、すべての html および htm ファイルが直接提供され、拡張子が「lift」のファイルを処理する必要があるというルールを追加したいと考えています。次のようなことをするのは簡単に見えます:

LiftRules.liftRequest.prepend {
  case Req(path, extension, tpe) => extension match {
    case "html" | "htm" => false
    case "lift" => true
  }
}

残念ながら、この場合、コンパイラは、最初の関数がcase常に一致するため、部分関数がどこでも定義されていると見なします。matchすべての受信リクエストに一致しない可能性があるのは、ネストされたものです。そして、リクエストが一致しない場合は、 aMatchErrorがスローされます。

質問

match部分関数を定義するときにコンパイラにネストされたステートメントを考慮させる簡単な方法はありますか、またはこのようにネストされたすべての条件をインライン化する唯一の方法はありますか?

LiftRules.liftRequest.prepend {
  case Req(path, extension, tpe) if extension == "html" || extension == "htm" => false
  case Req(path, extension, tpe) if extension == "lift" => true
}

この例では、ほとんど実行可能ですが、可読性が低下し、すべてのチェックをインライン化すると非常に見苦しく見えるケースに直面しました。

4

1 に答える 1

23

この場合、次のように書くことができます。

LiftRules.liftRequest.prepend {
  case Req(path, "html" | "htm", tpe) => false
  case Req(path, "lift", tpe) => true
}

caseより複雑なケースでは、ネストされたステートメントの代わりに使用する独自のエクストラクタを定義する必要があります。

object CheckExtension {
  def unapply(ext: String) = ext match {
    case "lift" => Some(true)
    case "html" | "htm" => Some(false)
    case _ => None
  }
}

LiftRules.liftRequest.prepend {
  case Req(path, CheckExtension(valid), tpe) => valid
}

unapplyこれは、事前定義された関数が返され、の値を自由変数にSome割り当てる場合にのみ一致します。を返す場合、一致は生成されていません。SomevalidunapplyNone

于 2011-07-07T11:13:51.427 に答える