【问题标题】:case class inheritance from trait behaving unexpectedly从 trait 意外行为的案例类继承
【发布时间】:2020-07-19 06:55:52
【问题描述】:

我有一个Person 的特征,以及一个从这个特征继承的案例类,我希望我有一个函数,除了从PersonFuture[Person] 的函数之外,我会从@ 传递它987654328@ 到 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)

但得到编译错误:

【问题讨论】:

  • 它是逆变的。 MalePerson,但 Male => Future[Male] 不是 Person => Future[Person],因为它必须以 Male 的值传递。想象一下打电话给maleToFutureMale(aFemale)。如果你可以将它传递给somethingsomething 可以做到这一点
  • 那么我该怎么做呢?因为我确实想要这种行为,创建一个函数,该函数将采用继承自 Person 的类并在其上运行 something。例如,我想将男性功能从 matl 传递到未来的男性和女性到未来的女性到 something @AluanHaddad
  • 没有更多上下文,我会写def something[P <: Person](toFuture: P => Future[P]): Unit。但是,这取决于您使用该功能做什么。在您的示例中,它没有被调用。
  • 此外,Function1 的参数类型是逆变的,结果类型是协变的。 scala-lang.org/api/2.12.2/scala/Function1.html 这意味着您可以在那里拥有一个函数,其中输入是 Person 的超类型,结果是子类型。像 Kotlin 这样的其他语言通过 in/out 注释让新手更容易理解,在 scala 中我们有 + 和 -。 @AluanHaddad 你会把你的评论写成答案,这样我们就可以投票/接受它。

标签: scala variance


【解决方案1】:

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

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] 类型。函数类型确实有子类型关系。

函数类型的参数类型为contravariant,返回类型为covariant

一般来说,给定函数类型F,具有less 特定参数类型和更多 特定返回类型的函数类型是F 的子类型.

例如,以下是完全有效的

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

something(anyToFutureOfMale)

以上内容有效,因为Any => MalePerson => Person。由于PersonAny,因此将Person 传递给期望Any 的函数是完全合理的,同样,作为MalePerson,接收@987654351 非常合理@ 来自返回 Person 的函数。

【讨论】:

    【解决方案2】:

    那是因为您将子类型化与协/逆变性混合在一起。 男性是人,男性 => Future[Male] 不是人 => Future[Person]。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-15
      • 2013-08-21
      • 2013-12-30
      • 1970-01-01
      相关资源
      最近更新 更多