了解与子类的模式匹配

时间:2015-01-20 22:45:11

标签: scala pattern-matching

Lift有Box案例类。

我在Box[A]上编写了以下方法来匹配模式:

scala> import net.liftweb.common._
import net.liftweb.common._

scala> def foo[A](box: Box[A]) = box match { 
     |   case Empty | Failure(_, _, _) => true
     |   case Full(_)                  => false
     | }
foo: [A](box: net.liftweb.common.Box[A])Boolean

我写了这个方法,以了解ParamFailureFailure的子类,是否会在Failure(_, _, _)案例上进行模式匹配。

scala> val pf: Box[String] = ParamFailure("a", Empty, Empty, "blah")
pf: net.liftweb.common.Box[String] = ParamFailure(a, Empty, Empty, blah)

而且,确实如此。

scala> foo(pf)
res9: Boolean = true

我不清楚为什么ParamFailure会匹配Failure(_, _, _)。那是为什么?

2 个答案:

答案 0 :(得分:6)

这是继承的全部要点。如果SC的子类,那么您应该能够使用S 绝对无处不在的使用C(这称为Liskov Substitution Principle)。

包括模式匹配。

现在,如果你特别想知道你是否有S而不是C,你可以检查一下:

class C {}
class S extends C {}
val c: C = new S
c match {
  case s: S => println("Actually, I was an S")
  case _ => println("Guess I was some other kind of C")
}

但如果你问它是C,答案是肯定的:

c match {
  case c2: C => println("Yes, of course I am a C!")
  case _ => println("This would be super-weird.")
}

同样,添加模式匹配在此处不会改变任何内容;无论你是否知道类型然后手动拉出参数,或者Scala是否有助于为它们提供标识符,它的工作方式都是一样的。

case class P(p: Boolean) {}
object T extends P(true) {}
val p: P = T
p match {
  case P(tf) => println(tf)
  case _ => println("You will never reach here.")
}

答案 1 :(得分:2)

这就是案例类的定义in the spec

提取器接受case类的实例(即unapply方法接受C)并返回第一个参数列表的元素。

您可以想象其他定义,例如要求擦除类型完全相同,或者至少productArity是相同的。

模式匹配定义为testing for a shape,不仅或主要作为类型测试或相等测试。

事实上,constructor patterns的规范并未直接解决子类型问题:

  

模式匹配从构造函数调用创建的所有对象   C(V1,...,VN)

当然,子类构造必然会调用该构造函数。

回到a case class could extend another case class时,可能会有更高的期望,模式匹配会区分子类,但那是在我的时间之前:

$ scala27
Welcome to Scala version 2.7.7.final (OpenJDK 64-Bit Server VM, Java 1.6.0_33).
Type in expressions to have them evaluated.
Type :help for more information.

scala> case class A(i: Int)                       
defined class A

scala> case class B(j: Int, s: String) extends A(j)
defined class B           

scala> (B(7,"hi"): Any) match { case A(7) => 1 case B(_,_) => 2 }
res1: Int = 1

scala> B(7,"hi").productArity                      
res2: Int = 2

我从文法学校知道,有些骆驼有一个驼峰,有些有两个。