协方差和方法参数

Ryo*_*Oka 2 scala covariance contravariance

我的项目中有一个令人困惑的问题并且无法解决它,所以请帮助我!

这是一个简化原始代码的示例代码:

trait Sample[A] {
    def doit(param: A)
}

case object SampleEx1 extends Sample[Int] {
    def doit(param: Int) = {
        param + 0
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我需要根据A外部原因进行协方差,但是如果注释掉它会导致错误:

trait Sample[+A] {
    def doit(param: A) // ERR: covariant type A occurs in contravariant position in type A of value param
}

case object SampleEx1 extends Sample[Int] {
    def doit(param: Int) = {
        param + 0
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我stacoverflow并找到另一种类型的解决方案B,但然后发生另一个错误:

trait Sample[+A] {
    def doit[B >: A](param: B)
}

case object SampleEx1 extends Sample[Int] {
    def doit[Int](param: Int) = {
        param + 0 // type mismatch; found : Int(0) required: String
    }
}
Run Code Online (Sandbox Code Playgroud)

显然param不再Int是因为[B >: Int].

我尝试用自己和谷歌解决这个问题,但无法得到它.有人可以帮忙吗?非常感谢!:))

Eri*_*lun 5

第一个错误covariant type A occurs in contravariant position in type A of value param意味着如果泛型类型Foo声明自己在T(即Foo[+T])上是协变的,则意味着它的方法只能返回T而不需要它.否则将违反类型一致性.例如,您可以传入一个需要的Sample[Dog]地方的实例Sample[Animal],然后可以调用doit(new Duck)它,即使Sample[Dog]#doit只能处理实例Dog.但是,在这种情况下,返回值的行为完全相反(我会让你弄明白为什么).

不过这个

def doit[Int](param: Int)
Run Code Online (Sandbox Code Playgroud)

means doit有一个名为的参数Int,它与该Int类型无关(虽然它确实看起来像第一次印象一样,这就是为什么你永远不应该使用与其他/内置类型的名称一致的类型参数名称).所以你得到的错误是因为Int在那个上下文中意味着"任何类型",并且+在任何类型上使用将回退到字符串连接而不是算术加法.

相反,你需要(正确地继承Sample[+A]):

def doit[B >: Int](param: B)
Run Code Online (Sandbox Code Playgroud)

但是,这仍然不允许你做加法,param因为param现在是任何超类型Int,而不是Int它自己或其子类型.

所以我看不出你怎么能"修复"这个 - 方差的工作方式从根本上说不允许泛型类型在方法参数上协变.这与Scala无关.但请参阅http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/http://docs.scala-lang.org/tutorials/tour/variances.html以获取更多信息关于方差如何工作以及为什么它必须像它一样工作(在任何语言中实现正确的方差规则).

我认为在Stackoverflow上获得一个非常有用的答案的一般方法是描述你真正需要实现的内容,而不仅仅是你到目前为止所做的实现.