2016-11-13 13 views
3

Этот вопрос был подтвержден Роланд Куном в этом post, однако, несмотря на несколько комментариев с просьбой о подробностях, он не удосужился поделиться полным ответом.Сохраняемые аргументы типа в Akka получают

Вот что я хочу сделать: у меня есть класс-обертка case class Event[T](t: T), из которого я отправляю экземпляры актеру Акка. В методе receive этого актера я хочу различать Event[Int] и Event[String], что, очевидно, не так просто из-за стирания типа.

Что упоминает Роланд Кун в упомянутом сообщении, так это то, что «есть только один способ сделать это», то есть воплощать информацию типа в сообщении. Так что я сделал это:

case class Event[T](t: T)(implicit val ct: ClassTag[T]) 

Несмотря на то, спросил разными людьми, чтобы обеспечить это, Роланд Кун не говорит, что на самом деле сделать в рамках метода receive тогда. Вот что я пробовал.

def receive = { 
    case e: Event => 
    if (e.ct.runtimeClass == classOf[Int]) 
     println("Got an Event[Int]!") 
    else if (e.ct.runtimeClass == classOf[String]) 
     println("Got an Event[String]!") 
    else 
     println("Got some other Event!") 
    case _ => 
    println("Got no Event at all!") 
} 

Это лучшее, что я мог придумать, как это трудно, чтобы обернуть свою голову вокруг отражения джунглей Скала. Это не компиляции, хотя:

value ct is not a member of Any 
else if (e.ct.runtimeClass == classOf[String]) 
     ^

Таким образом, я спрашиваю конкретно о том, что метод receive должен выглядеть.

+1

Это выглядит прямо ко мне (за исключением того, проще сравнивать 'ClassTag' непосредственно:' e.ct == ClassTag.Int' и 'e.ct == classTag [String]'). В сообщении об ошибке у вас есть 's.ct', который отсутствует в коде. –

+0

Изменено на 'e.ct'. Я упростил приведенный выше код, чтобы быть автономным в этом сообщении. Однако сообщение об ошибке, которое я скопировал из реального кода. Хороший улов, спасибо! – lambdarookie

+1

Вам также нужно исправить 'case e: Event [_]'. После этого он компилируется: http://scastie.org/23724. –

ответ

1

После фиксации ошибка Event takes type parameters:

def receive = { 
    case e: Event[_] => 
    if (e.ct.runtimeClass == classOf[Int]) 
     println("Got an Event[Int]!") 
    else if (e.ct.runtimeClass == classOf[String]) 
     println("Got an Event[String]!") 
    else 
     println("Got some other Event!") 
    case _ => 
    println("Got no Event at all!") 
} 

код компилируется. Это может быть немного упрощена, не глядя внутрь ClassTag с (конечно, реализация ClassTag#equals собирается сравнить классы):

import scala.reflect.{ClassTag, classTag} 

def receive = { 
    case e: Event[_] => 
    if (e.ct == ClassTag.Int) // or classTag[Int] 
     println("Got an Event[Int]!") 
    else if (e.ct == classTag[String]) 
     println("Got an Event[String]!") 
    else 
     println("Got some other Event!") 
    case _ => 
    println("Got no Event at all!") 
} 
0

Вы также можете сделать по шаблону на внутренней переменной внутри вложенного класса в тогда это более кратким, вы можете использовать различные трюки для сравнения с шаблоном, и вам даже не нужно ClassTag: например

case class Event[T](t: T)  

def receive = { 
    case Event(t: Int) => 
    println("Int") 
    case Event((_: Float | _: Double)) => 
    println("Floating Point") 
    case Event(_) => 
    println("Other") 
}