scala雾中风景(13): 模式匹配中的逻辑或

bigbull_提的问题,说在看akka的源码时,模式匹配有这样的用法,之前没有看到过:

def isManagementMessage(msg: Any): Boolean = 
  msg match { 
    case _: AutoReceivedMessage | _: Terminated | _: RouterManagementMesssage ⇒ true 
    case _ ⇒ false 
  }

自己尝试:

val a = 1 
val b = a match { case _:String | _:Int => "str or int" } 

却报错。

这是模式匹配可以对多个条件一起匹配的情况。假设有2个case class定义如下:

scala> case class A(p1:Int, p2:Int)
defined class A

scala> case class B(p1:String, p2:String)
defined class B

现在我们想在模式匹配的时候,判断目标是否匹配A或B,可以这样写:

scala> def foo(msg:Any) = msg match { case A(_,2) | B(_,_) => println("ok") }
foo: (msg: Any)Unit

scala> foo(A(1,2))
ok

上面使用的是构造器模式混合通配符,如果我们不关心匹配时解构参数,只关心类型,可以用下面的方式来写:

scala> def foo(msg:Any) = msg match { case _:A | _:B => println("ok") }
foo: (msg: Any)Unit

scala> foo(A(1,2))
ok

这里注意,上面的类型匹配不能简化为 case _: A | B 因为这样写B代表的是伴生对象,是常量匹配:

scala> def foo(msg:Any) = msg match { case _:A | B => println("ok") }
foo: (msg: Any)Unit

scala> foo(A(1,2))
ok

scala> foo(B(1,2))
<console>:13: error: type mismatch;
found   : Int(1)
required: String
          foo(B(1,2))
                ^
scala> foo(B)
ok

上面的匹配表达式表示匹配A类型,或者B伴生对象(常量)。

而原先测试时,使用的

scala> val a = 1  // 这里已经推导a为Int类型
scala> val b = a match { case _:String | _:Int => "str or int" }
<console>:8: error: scrutinee is incompatible with pattern type;

这其实也可以给出警告而不是错误,scala编译器比较严格直接报错误了,要通过编译,可以把a的类型设置的泛一些:

scala> val a:Any = 1
a: Any = 1

scala> val b = a match { case _:String | _:Int => "str or int" }
b: String = str or int  

scala雾中风景(13): 模式匹配中的逻辑或》上有2个想法

  1. scala> case class A(a:Int)
    defined class A

    scala> case class B(a:Int)
    defined class B

    scala> val a = A(1)
    a: A = A(1)

    scala> val b = a match { case _:A | _:B => “str or int” }
    :22: warning: fruitless type test: a value of type A cannot also be a B
    val b = a match { case _:A | _:B => “str or int” }
    ^
    b: String = str or int

    使用case class A或者B就报搞warning,而不是error,不明白为什么Int和String就直接报错了

发表评论

电子邮件地址不会被公开。 必填项已用*标注