Как объяснить эти примеры сопоставления с образцом?
Я написал несколько событий в 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], который я называю Vector[Any], поскольку Vector[Any] может быть Vector [String], он соответствует этому шаблону, и опять же, поскольку он действительно является вектором [ Int] Я маскирую как Vector[Any], печать тоже в порядке.
Может ли кто-нибудь объяснить эти наблюдения сопоставления с образцом?
и как мне настроить сообщения, чтобы мое состояние могло обрабатывать оба сообщения Vector[A] и Vector [B]?
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!