【问题标题】:How to explain these pattern matching examples?如何解释这些模式匹配示例?
【发布时间】:2016-09-23 08:46:12
【问题描述】:

我在 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 可以匹配一个字符串,但打印的是 java.lang.Integer。所以我应该把它想象成我有一个向量[Int],我说它是一个向量[Any],因为 Vector[Any] 可能是一个 Vector[String] 它匹配该模式,并且再次因为它确实是一个向量 [ Int] 我屏蔽为 Vector[Any] 打印也很好。

有人能解释一下这些模式匹配观察吗?

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

【问题讨论】:

  • AB 是什么?可以发minimal reproducible example吗?
  • A 和 B 是案例类。一个完整且可验证的示例(从某种意义上说,您可以运行它,对于 Akka FSM 将需要更多“不必要的”代码。其他代码将运行(复制和过去)。
  • 问题不在于 FSM,而在于模式匹配和类型。可以隔离问题并轻松创建可重现的问题。
  • @Yuval。我写了我的 akka 示例,以及一些我认为与之相关的模式匹配“工件”。由于我不确定如何将基于 akka 的问题完美地转换为更简单的模式匹配表示,所以我按原样写了我的问题。对我来说幸运的是,有人能够提供一些对我很有价值的见解。
  • 太棒了,真的。但更一般地说,人们更容易采用不工作的完整示例并使用它来理解手头的问题。创建一个可能很困难,但肯定会扩大受众提供帮助的能力。

标签: scala pattern-matching akka-fsm


【解决方案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!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 2016-07-14
    • 2019-01-06
    • 2013-09-23
    • 1970-01-01
    • 2010-09-19
    • 2010-11-06
    相关资源
    最近更新 更多