1

我认为这是关于协方差,但我在这个话题上很弱......

我有一个通用的 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)

比我有更大类型fu的人可以解释一下,1)如果我想做的事情是可能的(或合理的,就此而言),以及2)如果是这样,如何解决event2CC。谢谢!

4

2 回答 2

5

在我看来,您可以返回的最好的东西是 EventCC:

def event2CC(event: Event): EventCC

T 的类型不能在编译时更具体。只有在运行时我们才知道 T 是否精确LoginFollow,这仅取决于事件值。

于 2010-04-23T01:38:14.977 回答
1

如果您希望能够在模式匹配中使用事件,您可以为它们定义一个提取器:

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!"
}
于 2010-04-23T03:21:13.177 回答