case class 从 trait 继承异常行为

case class inheritance from trait behaving unexpectedly

我有一个 Person 的特征,以及一个继承自这个特征的案例 class,我希望如果我有一个函数,除了从 PersonFuture[Person] 并且我会将它从 Male 传递给 Future[Male] ,这将通过。像这样:

trait Person {
  val name: String
  val age: Int
}

case class Male (override val name: String, override val age: Int, height: Double) extends Person

val male1 = Male(name = "John", age = 30, height = 1.80)

def something(person: Person => Future[Person]): Unit = {
  println(s"person is $person")
}

def maleToFutureMale (male: Male) = Future.successful(male)

something(maleToFutureMale)

但出现编译错误:

这与 case 类 或 traits 无关,它与函数子类型有关。

Scala 拒绝此类代码,因为 MalePersonMale => Future[Male] 不是 Person => Future[Person]

要理解原因,请考虑以下类型

case class Female(val name, val age) extends Person

以及您的 something 方法的以下增量

def something(personToFuture: Person => Future[Person]): Unit = {
  val future = personToFuture(Female("Lisa", 53))
}

以上代码完全正确。我们可以将 Female 传递给 personToFuture 因为 FemalePerson.

如果语言允许我们将 maleToFutureMale 传递给 something,那么它将允许我们将 Female 传递给需要 Male 的函数。

所有这些并不是说函数类型是不变的,您传递给 something 的参数必须具有类型 Person => Future[Person]。函数类型确实有子类型关系。

函数类型在它们的 return 类型中是 contravariant in their parameter types and covariant

一般来说,给定一个函数类型,F,一个具有 less 特定参数类型和 more 的函数类型特定 return 类型是 F.

的子类型

例如,以下是完全有效的

val anyToFutureOfMale: Any => Future[Male] = _ => Future.successful(Male("Robert", 39, 1.8))

something(anyToFutureOfMale)

以上是有效的,因为 Any => MalePerson => Person。由于 PersonAny,因此将 Person 传递给期望 Any 的函数是完全合理的,同样,由于 MalePerson 从函数 return 接收 Person.

Male 听起来很完美

那是因为您将子类型与 co/contravariance 混用了。 男性是一个人,一个男性=>未来[男性]不是一个人=>未来[人]。