来自 trait 行为异常的 case 类继承

Joh*_*igs 0 scala variance

我有一个 traitPerson和一个继承自这个 trait 的 case 类,我希望如果我有一个函数,除了一个来自Personto的函数Future[Person],我会把它 func from MaletoFuture[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)
Run Code Online (Sandbox Code Playgroud)

但得到编译错误:

在此处输入图片说明

Alu*_*dad 5

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

Scala 拒绝这样的代码,因为虽然 aMale是 a Person,但 aMale => Future[Male]不是 a Person => Future[Person]

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

case class Female(val name, val age) extends Person
Run Code Online (Sandbox Code Playgroud)

以及您something方法的以下增量

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

上面的代码是完全正确的。我们可以传递 a FemaletopersonToFuture因为 aFemale是 a Person

如果该语言允许我们传递maleToFutureMaleto something,那么它将允许我们将 a 传递Female给期望 a 的函数Male

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

函数类型的参数类型是逆变的,返回类型是协变的

一般来说,给定一个函数类型 ,F具有较少特定参数类型和特定返回类型的函数类型是 的子类型F

例如,以下是完全有效的

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

something(anyToFutureOfMale)
Run Code Online (Sandbox Code Playgroud)

以上是有效的,因为 anAny => Male是 a Person => Person。由于 aPerson是 an Any,将 a 传递Person给期望 an 的函数是完美的Any,同样,作为a ,从返回 a 的函数接收 aMale也是Person完美MalePerson