読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

case classの可変長引数をパターンマッチでごにょごにょしたかった

Scala

ざっくり言うと、こういう流れです。

// 定義する
scala> case class Hoge(xs: Int*)
defined class Hoge

// 普通にパターンマッチしてもエラー
scala> Hoge(1,2,3) match {case Hoge(xs) => xs.sum }
<console>:10: error: value sum is not a member of Int
              Hoge(1,2,3) match {case Hoge(xs) => xs.sum }
                                                     ^

// _*と書くとコンパイルは通るが全部捨てられる
scala> Hoge(1,2,3) match {case Hoge(_*) => 0 }
res1: Int = 0

// 全部捨てられるので、こういう書き方は出来ない
scala> Hoge(1,2,3) match {case Hoge(_*) => _*.sum }
<console>:1: error: ';' expected but '.' found.
       Hoge(1,2,3) match {case Hoge(_*) => _*.sum }
                                             ^
// @をつけるとよい。これはHaskellでいうところのasパターンであるという認識
scala> Hoge(1,2,3) match {case Hoge(xs @_*) => xs.sum }
res2: Int = 6

これはどうも技術的にはType Ascriptionと呼ばれる技術みたいである。訳がよくわからない。

stackoverflow.com

追記

なお、x,xsとかx,y,xsみたいな書き方も出来る

scala> Hoge(1,2,3) match {case Hoge(x, xs @_*) => x }
res0: Int = 1

scala> Hoge(1,2,3) match {case Hoge(x, xs @_*) => xs }
res1: Seq[Int] = WrappedArray(2, 3)

scala> Hoge(1,2,3,4) match {case Hoge(x, y, zs @_*) => x }
res2: Int = 1

scala> Hoge(1,2,3,4) match {case Hoge(x, y, zs @_*) => y }
res3: Int = 2

scala> Hoge(1,2,3,4) match {case Hoge(x, y, zs @_*) => zs }
res4: Seq[Int] = WrappedArray(3, 4)

scala> Hoge(1,2,3,4) match {case Hoge(x, y, zs @_*) => (x,y,zs) }
res0: (Int, Int, Seq[Int]) = (1,2,WrappedArray(3, 4))