【问题标题】:Contravariance in scalascala中的逆变
【发布时间】:2016-07-05 15:28:51
【问题描述】:

我是 scala 的新手。我试图弄清楚整个逆变关系是如何工作的。我了解协变和不变的概念,并且我也知道如何在实践中实现它们。 我也了解逆变(协方差的逆)的概念以及它是如何在 Scala 的 Function1 特征中实现的。它为您提供了一个抽象,而无需为不同的类重新定义 Function1 实现。但是,我还是没完全明白,奇怪?现在,我快到了……我怎样才能用逆变来解决以下问题:

class GarbageCan[-A] {

  def doSomething(a: A): Unit ={
    // do something with 'a' of subtype that is not possible with the supertype
  }

}

def setGarbageCanForPlastic(gc: GarbageCan[PlasticItem]): Unit = {

}

以上示例摘自http://blog.kamkor.me/Covariance-And-Contravariance-In-Scala/。关于这个主题的一个非常好的解释。层次结构如下:Item(基类)-> PlasticItem(子类)-> PlasticBottle(子类的子类)

setGarbageCanForPlastic 函数接受类型为 PlasticItem 的 GarbageCan。因为Parameterized类型是逆变的,所以下面的语句是完全合法的:

setGarbageCanForPlastic(new GarbageCan[Item])

现在,doSomething 函数接受一个逆变的 Type 参数。如果我不知道该类型是基类“Item”还是子类“PlasticItem”,我该如何使用这种类型?我可以做一些在子类中而不是在基类中允许的事情。如果这是一个协变参数,那就没问题了,子类继承了基类的所有内容。

我弄丢了吧?...希望有人能帮帮我。

【问题讨论】:

  • 为什么只担心GarbageCan[Item]?例如,有什么可以阻止某人创建GrabageCan[Option[List[Int]]]?暂时忽略逆变方差。即使只是GrabageCan[A],您如何想象您的doSomething 会起作用?
  • 好问题...它应该只用作正文中的“类型”?
  • 好吧,我不确定你所说的“它”是什么意思,以及你在说谁的“身体”,所以我不知道 :) 底线是,你首先 提出一个实际用例,然后然后 看看逆变/协方差/不变性是否适合它,而不是相反。

标签: scala inheritance functional-programming


【解决方案1】:

首先,doSomething 方法实际上除了基本上丢弃 a 之外不能做任何事情,因为它不知道 A 是什么。为了让它更有用,你需要一个像class GarbageCan[-A <: Item] 这样的绑定。

现在,假设setGarbageCanForPlastic(gc) 调用gc.doSomething(new PlasticItem)。因为GarbageCan[A] 中的A 是逆变的,所以我们有GarbageCan[Item] <: GarbageCan[PlasticItem] <: GarbageCan[PlasticBottle]。实际上,函数调用setGarbageCanForPlastic(new GarbageCan[Item])) 是安全的,因为GarbageCan[Item]doSomething 可以处理任何Item,包括PlasticItem,而调用setGarbageCanForPlastic(new GarbageCan[PlasticBottle])) 是不安全的,因为GarbageCan[PlasticBottle]doSomething 可能不能够使用PlasticItem,不一定是PlasticBottle

【讨论】:

  • 太棒了!感谢您的详细说明。
猜你喜欢
  • 2015-02-09
  • 2016-07-27
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 2020-01-25
  • 2013-11-29
相关资源
最近更新 更多