【问题标题】:Covariance and method parameters协方差和方法参数
【发布时间】:2014-04-23 16:22:51
【问题描述】:

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

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

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

case object SampleEx1 extends Sample[Int] {
    def doit(param: Int) = {
        param + 0
    }
}

现在我需要出于外部原因使 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
    }
}

所以我 stacoverflowed 并找到了另一种类型 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
    }
}

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

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

【问题讨论】:

    标签: scala covariance contravariance


    【解决方案1】:

    第一个错误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)
    

    表示doit 有一个名为Int 的类型参数,它与Int 类型无关(尽管第一印象确实如此,这就是为什么你不应该使用类型参数名称的原因与其他/内置类型的名称一致)。所以你得到的错误是因为Int 在那个上下文中意味着“任何类型”,并且在任何类型上使用+ 都会退回到字符串连接而不是算术加法。

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

    def doit[B >: Int](param: B)
    

    但是,这仍然不允许您对 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 上获得真正有用​​的答案的更好方法通常是描述您真正需要实现的目标,而不仅仅是您迄今为止一直在进行的实现。

    【讨论】:

    • 打败我! ;) 我唯一要补充的是doit 可能没有有用的实现,因为Sample 上的协方差不会让您将param 限制为比Any 更好的任何东西。
    • @wingedsubmariner:我想我在你写评论的时候添加了那部分...... :)
    • 感谢您的回答!所以我需要想出另一种方法来实现它:/
    猜你喜欢
    • 1970-01-01
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-22
    相关资源
    最近更新 更多