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

Я записал некоторые события в FSM и обнаружил кое-что, что не могу объяснить при сопоставлении с образцом. Я думал, что следующее было совершенно законным, то есть я могу отправить этому актеру либо сообщение, которое является вектором [A], либо вектором [B].

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

Однако, если я отправлю актеру сообщение vector[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, но печать java.lang.Integer. Итак, я должен думать об этом, как о том, что у меня есть вектор [Int], который я называю Vector [Any], поскольку Vector [Any] может быть Vector [String], он соответствует этому шаблону, и опять же, поскольку это действительно вектор [ Int] Я маскирую как Vector[Any], печать тоже в порядке.

Может ли кто-нибудь объяснить эти наблюдения сопоставления с образцом?

и как мне настроить сообщения, чтобы мое состояние могло обрабатывать как сообщения Vector[A], так и Vector[B]?


person stian    schedule 23.09.2016    source источник
comment
Что такое A и B? Можете ли вы опубликовать минимально воспроизводимый пример?   -  person Yuval Itzchakov    schedule 23.09.2016
comment
A и B — классы случаев. Полный и проверяемый пример (в том смысле, что вы могли бы его запустить, потребует гораздо больше ненужного кода для Akka FSM. Другой код будет работать (копировать и вставлять).   -  person stian    schedule 23.09.2016
comment
Вопрос на самом деле не о FSM, а о сопоставлении с образцом и типах. Можно было бы изолировать проблему и легко создать воспроизводимую.   -  person Yuval Itzchakov    schedule 23.09.2016
comment
@Юваль. Я написал свой пример akka и некоторые артефакты сопоставления с образцом, которые, как я думал, связаны. Поскольку я не был уверен, как идеально перевести мои проблемы на основе akka в более простое представление сопоставления с образцом, я написал свой вопрос как есть. К счастью для меня, кто-то смог внести свой вклад в некоторые идеи, которые были ценны для меня.   -  person stian    schedule 23.09.2016
comment
Это здорово, правда. Но в целом людям проще взять нерабочий, полный пример и поэкспериментировать с ним, чтобы понять проблему. Создать его может быть сложно, но он определенно расширяет возможности аудитории.   -  person Yuval Itzchakov    schedule 23.09.2016
comment
К счастью, мне удалось получить помощь от того, как я представил проблему. Так что я счастлив, и, надеюсь, вопросы и ответы могут быть полезны и другим.   -  person stian    schedule 23.09.2016


Ответы (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!
person pamu    schedule 23.09.2016