Использование подтипов и возвращаемых типов в Scala для обработки общего объекта в определенный - PullRequest
1 голос
/ 23 апреля 2010

Я думаю, что речь идет о ковариации, но я слаба по теме ...

У меня есть универсальный класс Event, используемый для таких вещей, как постоянство базы данных, скажем так:

class Event(
  subject: Long,
  verb: String,
  directobject: Option[Long],
  indirectobject: Option[Long],
  timestamp: Long)
{
  def getSubject = subject
  def getVerb = verb
  def getDirectObject = directobject
  def getIndirectObject = indirectobject
  def getTimestamp = timestamp
}

Однако у меня много разных глаголов событий, и я хочу использовать сопоставление с образцом и тому подобное с этими различными типами событий, поэтому я создам несколько соответствующих классов дел:

trait EventCC
case class Login(user: Long, timestamp: Long) extends EventCC
case class Follow(
  follower: Long,
  followee: Long,
  timestamp: Long
) extends EventCC

Теперь вопросКак я могу легко преобразовать общие События в конкретные классы дел.

Это мой первый удар по этому вопросу:

def event2CC[T <: EventCC](event: Event): T = event.getVerb match {
  case "login" => Login(event.getSubject, event.getTimestamp)
  case "follow" => Follow(
    event.getSubject,
    event.getDirectObject.getOrElse(0),
    event.getTimestamp
  )
  // ...
}

К сожалению, это неправильно.

<console>:11: error: type mismatch;
 found   : Login
 required: T
             case "login" => Login(event.getSubject, event.getTimestamp)
                             ^
<console>:12: error: type mismatch;
 found   : Follow
 required: T
             case "follow" => Follow(event.getSubject, 
event.getDirectObject.getOrElse(0), event.getTimestamp)

Может ли кто-нибудь с большим типом фу, чем я, объяснить, если: 1) если то, что я хочу сделать, возможно (или разумно, если на то пошло), и 2) если так, как исправить event2CC.Спасибо!

Ответы [ 2 ]

5 голосов
/ 23 апреля 2010

Мне кажется, что лучшее, что вы можете вернуть, это EventCC:

def event2CC(event: Event): EventCC

Тип T не может быть более конкретным во время компиляции. Только во время выполнения мы знаем, является ли T точно Login или Follow, и это зависит только от значений события.

1 голос
/ 23 апреля 2010

Если вы хотите использовать События в сопоставлении с образцом, вы можете определить для них экстрактор:

object Event {
  def unapply(evt: Event): Some((Long, String, Option[Long])) = 
    Some(evt.getSubject, evt.getVerb, evt.getDirectObject)
}

val evt: Event = retrieveEventFromEther()
evt match {
  case Event(_, "login", _) => "It was a login!"
  case Event(_, "follow", Some(_)) => "It was a follow with a direct object!"
}
...