函数定义中的类型边界错误

Error with type bounds in function definition

我有一些 class 层次结构:

trait Params
trait ParamsWithName extends Params {
  val name: String
}
case class ParamsWithNameAndValue(name: String, value: String) extends ParamsWithName

我想实现一些 classes 来使用它们。以下作品:

trait Worker[T <: ParamsWithName] {
  def work(parameters: T): String = parameters.name
}

class SimpleWorker extends Worker[ParamsWithNameAndValue] {
  override def work(parameters: ParamsWithNameAndValue): String = s"${parameters.name} + ${parameters.value}"
}

以下没有:

trait Worker {
  def work[T <: ParamsWithName](parameters: T): String = parameters.name
}

class SimpleWorker extends Worker {
  override def work[ParamsWithNameAndValue](parameters: ParamsWithNameAndValue): String = s"${parameters.name} + ${parameters.value}"
}

错误是:

error: value name is not a member of type parameter ParamsWithNameAndValue
  override def work[ParamsWithNameAndValue](parameters: ParamsWithNameAndValue): String = s"${parameters.name} + ${parameters.value}"
error: value value is not a member of type parameter ParamsWithNameAndValue
  override def work[ParamsWithNameAndValue](parameters: ParamsWithNameAndValue): String = s"${parameters.name} + ${parameters.value}"

我想明白为什么会这样。

Scala 版本为 2.12。

这个:

trait Worker[T <: ParamsWithName] {
  def work(parameters: T): String = parameters.name
}

意味着 Worker 类型本身是 T 的参数(必须是 ParamsWithName 的子类型)。这意味着 Worker 的具体实例仅适用于 T

的一种具体类型

因此,这里:

class SimpleWorker extends Worker[ParamsWithNameAndValue] {

你是说 SimpleWorker 类型是 Worker[ParamsWithNameAndValue] 的子类型,这意味着 SimpleWorker 的所有实例都是 Worker[ParamsWithNameAndValue]

的实例

然而,这:

trait Worker {
  def work[T <: ParamsWithName](parameters: T): String = parameters.name
}

意味着 Worker 的任何实例都有一个方法 work,它是 T 的参数(必须是 ParamsWithName 的子类型).暗示任何 Worker 必须能够处理任何可能的类型 T

因此,这里:

class SimpleWorker extends Worker {
  override def work[ParamsWithNameAndValue](parameters: ParamsWithNameAndValue): String = s"${parameters.name} + ${parameters.value}"
}

您不仅有语法错误,还有概念问题。
因为你想说 SimpleWorker 上的 work 方法只能接受 ParamsWithNameAndValue 但那将违反 Liskov 替换原则。


总之,第一种方法是对您想要的意图进行编码的方法。