2010年3月3日水曜日

[Scala] valの左辺にパターンマッチが使える

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
今日の第4回Scala言語仕様輪読会での収穫。

pがパターンの時、val p = eは以下の様に展開される。
val $x = e match {case p => (x1, . . . , xn)}
val x1 = $x._1
. . .
val xn = $x._n
The Scala Language Specification(PDF)のp.36参照(タプルが{}になっているのは古い仕様?なので↑では()に直しています)。

簡単な例だと、タプルを使って同時にvalに代入できる。
val (x, y) = (1, 2)
// ↑は↓に展開され
val tmp = (1, 2) match {case (a, b) => (a, b)}
val x = tmp._1
val y = tmp._2
// 結局↓と同じ
val x = 1
val y = 2

Liftで↓なコードがあって、意味が分からなかったのだが、やっと理解できた。
// net/liftweb/http/Req.scala l.275
case class ParamCalcInfo(paramNames: List[String],
            params: Map[String, List[String]],
            uploadedFiles: List[FileParamHolder],
            body: Box[Array[Byte]])
// l.284
class Req(val path: ParsePath,
          val contextPath: String,
          val requestType: RequestType,
          val contentType: Box[String],
          val request: HTTPRequest,
          val nanoStart: Long,
          val nanoEnd: Long,
          private[http] val paramCalculator: () => ParamCalcInfo, // *2
          private[http] val addlParams: Map[String, String]) extends HasParams
{
// (省略)
// l.342
  lazy val ParamCalcInfo(paramNames: List[String],  // *1
            _params: Map[String, List[String]],
            uploadedFiles: List[FileParamHolder],
            body: Box[Array[Byte]]) = paramCalculator()
// (省略)
}
  1. なぜ突然valの後にcase classが…? と思ったらこれがパターンマッチ。コンストラクタで指定した関数paramCalculator(*2)がParamCalcInfoを返すので、ParamCalcInfoの各valがそれぞれparamNames, _params, uploadedFiles, bodyに束縛され、Req.body等として使える。つまり、↓の様に展開されているということと理解。
    val tmp = paramCalculator() match {
      case ParamCalcInfo(a, b, c, d) => (a, b, c, d)
    }
    val paramNames = tmp._1
    val _params = tmp._2
    val uploadedFiles = tmp._3
    val body = tmp._4
    

0 件のコメント:

コメントを投稿