'::'ケースクラスに関して2つの質問があります。
::として使用できます
case head :: tail => ...
それはどのように機能しますか?つまり、ScalaがListインスタンスを::ケースクラスと照合するために使用するフローは正確には何ですか?演算子opを使用したクラスMyClassがある場合、次のように使用できるopという名前のケースクラスを作成できますか?
case foo op bar => ....
?
scala> abstract class Stack {
| def push(n :Int):Stack
| }
defined class Stack
scala> final case class push(st :Stack,hd :Int) extends Stack {
| override def push(n :Int):Stack = new push(this,n)
| }
defined class push
scala> object NullStack extends Stack {
| override def push(n :Int):Stack = new push(null,n)
| }
defined module NullStack
scala> val s = NullStack.push(1).push(2)
s: Stack = push(push(null,1),2)
scala> def test(s :Stack) = s match { case st push i => println(st +"push " + i) }
test: (Stack)Unit
scala> test(s)
push(null,1)push 2
詳細については、Scalaでのプログラミングの301ページの「 sでのパターンマッチングについて」を参照してくださいList
。
「短所」パターン
x :: xs
は、中置操作パターンの特殊なケースです。式として見た場合、中置演算はメソッド呼び出しと同等であることはすでにご存知でしょう。パターンの場合、ルールは異なります。パターンとして見た場合、などのインフィックス操作は。p op q
と同等op(p, q)
です。つまり、中置演算子op
はコンストラクターパターンとして扱われます。特に、のような短所パターンx :: xs
はとして扱われ::(x, xs)
ます。::
これは、パターンコンストラクターに対応するという名前のクラスが必要であることを示唆しています。確かにそのようなクラスがあります。これは名前が付けられscala.::
ており、空でないリストを作成するクラスです。
実際、::がケースクラスであるという事実は、答えの半分にすぎません。これがパターンマッチングで機能する理由は、ケースクラスが定義されたときに自動的に生成されるオブジェクト::のエクストラクタがあるためです。便利なことに、::。unapplyはリストを返します。::はリストを拡張するためです。ただし、リストに同じトリックを使用したい場合は、リストが最終的なものであるため、リストを拡張することはできません。あなたができることは、期待される戻り署名を持つ適切なunapplyメソッドでオブジェクトを定義することです。たとえば、リストの最後の要素を照合するには、次のようにします。
object ::> {def unapply[A] (l: List[A]) = Some( (l.init, l.last) )}
List(1, 2, 3) match {
case _ ::> last => println(last)
}
(1 to 9).toList match {
case List(1, 2, 3, 4, 5, 6, 7, 8) ::> 9 => "woah!"
}
(1 to 9).toList match {
case List(1, 2, 3, 4, 5, 6, 7) ::> 8 ::> 9 => "w00t!"
}
エクストラクタは、2つの分解された要素のタプルを含むOptionを返す必要があります。