如何解释这些模式匹配示例?

时间:2016-09-23 08:46:13

标签: scala pattern-matching akka-fsm

我在FSM中写了一些事件,并发现了一些在模式匹配时无法解释的事情。我认为以下是完全合法的,也就是说我可以向这个演员发送一个消息,它是一个向量[A]或向量[B]。

when(State) {
    case Event(content: Vector[A], _) => {
      println("matched A")
      stay
   }
   case Event(content: Vector[B], _) => {
     println("matched B")
     stay
  }  
}

然而, 如果我向演员发送一个矢量[B]消息,它将导致

java.lang.ClassCastException: B cannot be cast to A

所以基本上它会尝试匹配第一个事件,而下一个匹配。

我试图制作一个更简单的模式匹配示例;

object Pattern extends App {
    val n = Vector(1,2,3)
    val s = Vector("S", "S", "S")
    n match{
       case e:Vector[String] => println("matched string")
       case v:Vector[Int] => println("matched int")
   }

}

这实际上不合法;

Error:(8, 12) pattern type is incompatible with expected type;
found   : Vector[String]
required: scala.collection.immutable.Vector[Int]
case e:Vector[String] => println("matched string")

但是,如果我执行以下演员,我可以运行我的代码;

object Pattern extends App {
  val n = Vector(1,2,3).asInstanceOf[Vector[Any]]
  val s = Vector("S", "S", "S")
  n match{
    case e:Vector[String] => println(n(0).getClass)
    case v:Vector[Int] => println("matched int")
  }
}

我觉得奇怪的是,我显然说Any可以匹配一个String,但是print是java.lang.Integer。所以我应该想到它,因为我有一个向量[Int]我说是Vector [Any],因为Vector [Any]可以是Vector [String]它匹配那个模式,并且因为它真的是一个向量[ Int]我掩饰为Vector [Any]打印也很好。

有人可以解释这些模式匹配观察吗?

我应该如何设置消息,以便我的状态可以处理Vector [A]和Vector [B]的消息?

1 个答案:

答案 0 :(得分:1)

由于jvm类型信息的类型擦除在运行时丢失,因此不直接支持这种模式匹配(与较高级别的类型匹配模式)。

以下是解决此问题的方法

相反,我建议你将矢量包装在另一个容器中。

sealed trait Vectors

case class VectorString(vs: Vector[String]) extends Vectors

case class VectorInt(vi: Vector[Int]) extends Vectors

def doStuff(v: Vectors) = v match {
 case VectorString(vs) => //be sure that vs is Vector[String]
 case VectorInt(vi) => 
}

模式匹配Scala中的泛型类型的方法

使用TypeTag

import scala.reflect.runtime.universe._

def handle[A: TypeTag](a: A): Unit =
  typeOf[A] match {
    case t if t =:= typeOf[List[String]] =>
      // list is a string list
      val r = a.asInstanceOf[List[String]].map(_.length).sum
      println("strings: " + r)

    case t if t =:= typeOf[List[Int]] =>
      // list is an int list
      val r = a.asInstanceOf[List[Int]].sum
      println("ints: " + r)

    case _ => // ignore rest
  }

val ints: List[Int] = Nil

handle(List("hello", "world")) // output: "strings: 10"
handle(List(1, 2, 3))          // output: "ints: 6"
handle(ints)                   // output: "ints: 0" it works!