Using Sub-Types And Return Types in Scala to Process a Generic Object Into a Specific One
I think this is about covariance but I'm weak on the topic...
I have a generic Event class used for things like database persistance, let's say like this:
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
}
However, I have lots of different event verbs and I want to use pattern matching and such with these different event types, so I will create some corresponding case classes:
trait EventCC
case class Login(user: Long, timestamp: Long) extends EventCC
case class Follow(
follower: Long,
followee: Long,
timestamp: Long
) extends EventCC
Now, the question is, how can I easily convert generic Events to the specific case classes.
This is my first stab at it:
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
)
// ...
}
Unfortunately, this is wrong.
<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)
Could someone with greater type-fu than me explain if, 1) if what I want to do is possible (or reasonable, for that matter), and 2) if so, how to fix event2CC
. Thanks!
It seems to me that the best thing you can return is EventCC:
def event2CC(event: Event): EventCC
The type of T cannot be made more specific at compile time. It's only at run-time that we know if T is precisely Login
or Follow
and this only depends on event values.
If you want to be able to use Events in pattern matching, you could define an extractor for them:
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!"
}
精彩评论