了解 Sub-类 的模式匹配
Understanding Pattern Matching with Sub-classes
电梯有 Box 个案例 class。
我写了下面的方法来匹配 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
我编写此方法是为了了解 ParamFailure
(Failure
的子class)是否会在 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(_, _, _)
。这是为什么?
这就是继承的全部意义所在。如果 S
是 C
的子类,那么您应该可以在使用 C
的所有地方 使用 S
(这被称为 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.")
}
这就是 case class 的定义方式 in the spec。
抽取器获取case的一个实例class(即unapply方法获取一个C)和returns第一个参数列表的元素
你可以想象其他定义,比如要求被擦除的类型完全一样,或者至少productArity
是一样的。
模式匹配定义为 testing for a shape,不仅或主要作为类型测试或相等性测试。
事实上,constructor patterns 的规范并未直接解决子类型问题:
The pattern matches all objects created from constructor invocations
c(v1,…,vn)
当然,subclass 构造必须调用该构造函数。
回到 a case class could extend another case class 时,人们可能对模式匹配能够区分子 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
我从文法学校知道,有些骆驼有一个驼峰,有些有两个。
电梯有 Box 个案例 class。
我写了下面的方法来匹配 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
我编写此方法是为了了解 ParamFailure
(Failure
的子class)是否会在 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(_, _, _)
。这是为什么?
这就是继承的全部意义所在。如果 S
是 C
的子类,那么您应该可以在使用 C
的所有地方 使用 S
(这被称为 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.")
}
这就是 case class 的定义方式 in the spec。
抽取器获取case的一个实例class(即unapply方法获取一个C)和returns第一个参数列表的元素
你可以想象其他定义,比如要求被擦除的类型完全一样,或者至少productArity
是一样的。
模式匹配定义为 testing for a shape,不仅或主要作为类型测试或相等性测试。
事实上,constructor patterns 的规范并未直接解决子类型问题:
The pattern matches all objects created from constructor invocations c(v1,…,vn)
当然,subclass 构造必须调用该构造函数。
回到 a case class could extend another case class 时,人们可能对模式匹配能够区分子 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
我从文法学校知道,有些骆驼有一个驼峰,有些有两个。