Почему Scala не выводит параметры типа при сопоставлении с шаблоном @
Я использую Scala 2.10.4 с akka 2.3.4. Я столкнулся с проблемой, когда вывод типа ведет себя не так, как я ожидал.
Приведенный ниже код иллюстрирует пример того, что я испытываю. У меня есть класс case, который обертывает сообщения с именемid
MyMessage
. Он параметризуется типом сообщения. Тогда у меня есть полезная нагрузка с именем MyPayload
, которая содержит String
.
Внутри актора (здесь я просто использую обычный объект с именем MyObject
, поскольку проблема не в частности, для akka) я сопоставляю шаблон и вызываю функцию, которая работает с моим типом полезной нагрузки MyPayload
.
package so
case class MyMessage[T](id:Long, payload:T)
case class MyPayload(s:String)
object MyObject {
def receive:PartialFunction[Any, Unit] = {
case m @ MyMessage(id, MyPayload(s)) =>
// Doesn't compile
processPayload(m)
// Compiles
processPayload(MyMessage(id, MyPayload(s)))
}
def processPayload(m:MyMessage[MyPayload]) = {
println(m)
}
}
По причинам, которых я не понимаю, паттерн patching с @
и неприменимым классом case не выводит параметр типа MyMessage[T]
. В приведенном выше коде я ожидал, что m
будет иметь тип MyMessage[MyPayload]
. Однако, когда я компилирую, он считает, что тип MyMessage[Any]
.
[error] PatternMatch.scala:9: type mismatch;
[error] found : so.MyMessage[Any]
[error] required: so.MyMessage[so.MyPayload]
[error] Note: Any >: so.MyPayload, but class MyMessage is invariant in type T.
[error] You may wish to define T as -T instead. (SLS 4.5)
[error] processPayload(m)
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 1 s, completed Aug 19, 2014 12:08:04 PM
Является ли это ожидаемым поведением? Если да, то что я неправильно понял о типе вывод в скале?
3 ответа:
Вы не можете извлечь параметры типа в сопоставлении с шаблоном - это ограничение текущей реализации и / или среды выполнения. Поскольку параметры типа стираются во время выполнения, для их восстановления потребуется много накладных расходов , поэтому нельзя использовать метод
unapply
, который принимает параметр типа в соответствии с шаблоном.В вашем случае это выглядит проще, потому что компилятор может просто вывести тип из аргументов экстрактора. Но в целом это не так просто и, вероятно, причина почему это даже не работает в вашем случае.
Смотритеэтот билет на долгую жизнь о проблеме.
Проблема, с которой вы столкнулись, - это стирание типа
JVM ничего не знает об универсальных типах во время выполнения, см.:
Как обойти стирание типа на Scala? Или, почему я не могу получить параметр типа моих коллекций?
Чтобы заставить его компилироваться, вы должны сказать компилятору эксплицитно, какой тип вы ожидаете
def receive:PartialFunction[Any, Unit] = { case message: MyMessage[MyPayload] => processPayload(message) }
Предупреждение: это все равно будет соответствовать любому MyMessage [_] и может вызвать исключения времени выполнения.
Обеспечить тип во время выполнения, вам нужно использовать TypeTags (см. ссылку выше)