简体   繁体   English

Scala:错误类型不匹配

[英]Scala: Error type mismatch

I am struggling with the type system. 我正在努力使用类型系统。 I get a "error: type mismatch" at the line 我在行中收到“错误:类型不匹配”

handler.addJob(job1)

It says found "MessageEvent" required "Event" 它说found "MessageEvent" required "Event"

I think that I need to somehow change the addJob method to pass in any Job with a type that extends Event but I can't figure out how to do that. 我认为我需要以某种方式更改addJob方法,以使用扩展Event的类型传递任何Job ,但我不知道该怎么做。

Also the line 还行

var jobs = List[Job[Event]]()

should probably take a job with a subtype of Event but again I don't know how to do that. 应该使用Event的子类型来工作,但我又不知道该怎么做。 Any help is appreciated. 任何帮助表示赞赏。

-Eric -埃里克

class EventHandler {
  var jobs = List[Job[Event]]()

  def receive(event: Event) {
    jobs.foreach {
      _.processEvent(event)
    }
  }

  def addJob(job: Job[Event]) {
    jobs = job :: jobs
  }
}

class Job[T <: Event] {
  var steps = List[(T => Unit)]()

  def addStep(step: (T => Unit)) {
    steps = step :: steps
  }

  def processEvent(event: T): Boolean = {
    steps.foreach(_.apply(event))
    return true
  }
}

class AppTest {
  def testApp {
    val handler = new EventHandler()
    val job1 = new Job[MessageEvent]
    job1.addStep {
      println(_)
    }
    handler.addJob(job1)
    handler.receive(new MessageEvent(new Message()))
  }
}

The problems you mention are easy to fix: 您提到的问题很容易解决:

class EventHandler {
  var jobs = List[Job[_]]()

  def receive(event: Event) {
    jobs.foreach {
      _.processEvent(event)
    }
  }

  def addJob(job: Job[_]) {
    jobs = job :: jobs
  }
}

But this shows another problem with the receive method: you need each job to process any Event . 但这显示了receive方法的另一个问题:您需要每个job来处理任何Event This can be fixed using Manifest s to work around type erasure: 可以使用Manifest来解决此问题,以解决类型擦除:

class Job[T <: Event : ClassManifest] {
  val clazz: Class[T] = implicitly[ClassManifest[T]].asInstanceOf[Class[T]]
  var steps = List[(T => Unit)]()

  def addStep(step: (T => Unit)) {
    steps = step :: steps
  }

  def processEvent1(event: Event): Boolean = {
    try {
      processEvent(clazz.cast(event))
    }
    catch {
      case e: ClassCastException => false
    }
  }

  def processEvent(event: T): Boolean = {
    steps.foreach(_.apply(event))
    return true
  }
}

Changing addJobs : 更改addJobs

def addJob[T <: Event](job: Job[T]) {
  jobs = job :: jobs
}

But jobs won't work with that, since Job[MessageEvent] is not a Job[Event] . jobs不与任何工作,因为Job[MessageEvent]不是Job[Event] The only way to get that is to make Job co-variant, but, unfortunately, you can't make Job co-variant as it is. 达到此目的的唯一方法是使Job协变,但是不幸的是,您无法使Job保持原样。

Why don't you, instead, completely removes Job 's parameterization and use Event internally? 您为什么不完全删除Job的参数并在内部使用Event You can then use T <: Event (like above in addJob ) with addStep and processEvent , if necessary. 然后,可以在addJobT <: Event (如上述addJob )与addStepprocessEvent使用。

Based on your example, it looks as though you'll be building the Job and EventHandler instances statically. 根据您的示例,似乎您将静态构建JobEventHandler实例。 In this case, you really don't need those classes at all! 在这种情况下,您实际上根本不需要这些类!

Starting with Job . Job开始。 This performs two roles: 它扮演两个角色:

  1. maintain a list of T => Unit functions 维护T => Unit功能的列表
  2. execute those functions 执行那些功能

(it's also worth noting that :: prepends, so steps will be executed in the reverse of the order they were added) (这也是值得注意的是::预先考虑,所以步骤将加入他们的顺序相反被执行)

Building and maintaining that list of functions at runtime (within a mutable list) can be completely avoided if you already know what they'll be when the thing compiles. 如果您已经知道事物在编译时会变成什么样子,则可以完全避免在运行时建立和维护该函数列表(在可变列表内)。 This is most naturally done with an aggregate function: 这最自然地是通过聚合函数完成的:

val job = (m: MessageEvent) => {
  log.debug(m)
  println(m)
  somethingElse(m)
}

Instead of holding a List[Job[Event]] , this means that EventHandler now holds a List[(T => Unit)] (as Job previously did). 而不是持有List[Job[Event]] ,这意味着EventHandler现在持有List[(T => Unit)] (就像Job以前所做的那样)。 So rinse and repeat... 所以冲洗并重复...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM