Как объяснить эти примеры сопоставления с образцом?

Я написал несколько событий в 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!
Другие вопросы по тегам