Scala案例类问题

8

我有两个关于'::' case类的问题。

'::'可以用作

case head :: tail => ...

它是如何工作的?也就是说,Scala使用什么流程来将List实例与:: case类匹配?假设我有一个名为MyClass的类,其中包含操作符op,我能否创建一个名为op的case类,以便我可以像这样使用:

case foo op bar => ....

?


2
这是一个重复的问题,真的。 - Daniel C. Sobral
我的问题不仅是为什么变量之间有'::',而且一个case class如何匹配另一个class的实例(原因是List#::创建:: case class的实例)。 - IttayD
eed3si9n 引用的文本在《Scala编程》(第1版)的PDF版本中的第331页。 - Eugen Labun
3个回答

5
     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

太棒了!诀窍在于List#::返回一个案例类::的实例。 - IttayD

3

这在《Scala编程》的第301页详细说明了,涉及到对List进行模式匹配。

“cons” 模式 x :: xs 是中缀操作模式的一种特殊情况。 您已经知道,当视为表达式时,中缀操作等同于方法调用。对于模式,规则 是不同的:当作为模式看待时,中缀操作如 p op q 等同于 op(p, q)。 也就是说,中缀运算符 op 被视为构造函数模式。 特别地,cons 模式如 x :: xs 被视为 ::(x, xs)。 这暗示着应该有一个名为 :: 的类与该模式构造函数对应。确实存在这样的类。 它被命名为 scala.::,正是构建非空列表的类。


2
实际上,:: 是一个 case 类的事实只是答案的一半。这个在模式匹配中起作用的原因是,对象 :: 有一个 提取器,当定义一个 case 类时会自动生成它。方便的是,::.unapply 返回一个列表,因为 :: 扩展了 List。如果你想对列表使用相同的技巧,你将无法扩展 List,因为它是 final 的。你可以定义一个具有预期返回签名的适当 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!"
}

提取器必须返回一个Option,其中包含两个拆分元素的元组。

我认为unapply在这里不适用 scala> val l = List(1, 2 , 3) l: List[Int] = List(1, 2, 3) scala> scala.::.unapply(l) <console>:6: error: type mismatch; found : List[Int] required: ::[?] val r = scala.::(1, Nil) r: ::[Int] = List(1)scala> scala.::.unapply(r)
res7: Some[List[Int]] = Some(List())因此,unapply仅适用于由case类实际构造的对象,而不适用于一般列表。
- IttayD
一个 case class 创建的 unapply 没有什么特别之处。请注意,List 是抽象的,实际上任何非空列表都是 scala.:: 的实例。List(1).isInstanceOf[::[Int]]这意味着您在模式匹配中匹配的实际上是 scala.:: 的实例(除非它是 Nil)。还要注意,一旦您只为 :: 重新定义了 unapply,List 的模式匹配就会中断:object :: {def unapply = false} - vdichev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接