简体   繁体   English

了解与子类的模式匹配

[英]Understanding Pattern Matching with Sub-classes

Lift has the Box case class. Lift有Box案例类。

I wrote the following method to pattern match on a Box[A] : 我在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

I wrote this method to learn if ParamFailure , which is a sub-class of Failure , would pattern match on the Failure(_, _, _) case. 我写了这个方法来了解ParamFailure ,它是一个Failure的子类,是否会在Failure(_, _, _)情况下模式匹配。

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

And, it did. 而且,确实如此。

scala> foo(pf)
res9: Boolean = true

It's not clear to me why ParamFailure would match to Failure(_, _, _) . 我不清楚ParamFailure为什么会匹配Failure(_, _, _) Why is that? 这是为什么?

This is the whole point of inheritance. 这是继承的全部要点。 If S is a subclass of C , then you should be able to use S absolutely everywhere that you use C (this is called the Liskov Substitution Principle ). 如果SC的子类,那么你应该能够在任何使用C 地方绝对使用S (这称为Liskov替换原则 )。

Pattern matching is included. 包括模式匹配。

Now, if you specifically want to tell if you have an S as opposed to a C , you can check for it: 现在,如果你特别想知道你是否有一个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")
}

But if you ask if it's a C , the answer is yes: 但如果你问它是否是C ,答案是肯定的:

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

Again, adding pattern matching changes nothing here; 再次,添加模式匹配在此不做任何改动; whether you know the type and then pull out the parameters by hand, or whether Scala helpfully gives you identifiers for them, it works the same way. 无论您是否知道类型,然后手动提取参数,或者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.")
}

This is just how case classes are defined in the spec . 这就是规范中定义案例类的方式。

The extractor takes an instance of the case class (that is, the unapply method takes a C) and returns the elements of the first parameter list. 提取器接受case类的实例(即,unapply方法接受C)并返回第一个参数列表的元素。

You could imagine other definitions, such as requiring that the erased type is exactly the same, or at least that productArity is the same. 您可以想象其他定义,例如要求擦除类型完全相同,或者至少productArity是相同的。

Pattern matching is defined as testing for a shape , and not only or primarily as a type test or equality test. 模式匹配被定义为测试形状 ,而不仅仅是或主要作为类型测试或相等测试。

In fact, the spec for constructor patterns doesn't directly address subtyping: 实际上, 构造函数模式的规范并没有直接解决子类型:

The pattern matches all objects created from constructor invocations c(v1,…,vn) 该模式匹配从构造函数调用c(v1,...,vn)创建的所有对象

Of course, subclass construction necessarily invokes that constructor. 当然,子类构造必然会调用该构造函数。

Back when a case class could extend another case class , there might have been a higher expectation that pattern matching would distinguish subclasses, but that was before my time: 一个case类可以扩展另一个case类时 ,可能会有更高的期望,模式匹配会区分子类,但那是在我的时间之前:

$ 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

I know from grammar school that some camels have one hump and others have two. 我从文法学校知道,有些骆驼有一个驼峰,有些有两个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM