【问题标题】:Can't understand why `trait Hello[+A] { def test[B<:A] }` can't be compiled不明白为什么 `trait Hello[+A] { def test[B<:A] }` 无法编译
【发布时间】:2014-06-18 16:57:57
【问题描述】:

我可以理解为什么下面的代码不能编译了:

trait Hello[+A] {
    def test[B<:A](x: B)
}

因为:

val child: Hello[String] = new Hello[String] {
    def test[B <: String](x: B) = x.substring(1)
}
val parent: Hello[Any] = child
parent.test(123) // child.test can't handle integer

但是我不能很好理解为什么下面的代码不能编译:

trait Hello[+A] {
    def test[B<:A]
}

不同的是后者没有参数,我们不能将任何值传递给test方法。

为什么编译器仍然认为它无效?

【问题讨论】:

    标签: scala generics contravariance type-systems


    【解决方案1】:

    当您尝试在 repl 中执行此操作时,它会说:

    scala> trait Hello[+A] {
         |     def test[B<:A](x: B)
         | }
    <console>:8: error: covariant type A occurs in contravariant position in type  <: A of type B
               def test[B<:A](x: B)
                        ^
    

    没错。想象一下,如果这是可能的,你可以:

    val x:Hello[Dog] = new Hello[Dog]{..}
    val y:Hello[Animal] = x
    y.test(Cat)//Oops
    

    关于参数,是什么让你认为它在没有任何参数的情况下是安全的。您可以使用 implicitly 获取变量并执行编译器不会阻止您的危险事情。示例:

    def test[B<:A]:B = this
    

    【讨论】:

    • 例子def test[B&lt;:A]:B = this不好。实际上,B 是不变的,它可能出现在返回类型的位置。查看可编译示例:trait Cat[-A] { def meow[B &lt;: A](x: B): B }
    • 我认为原因是B可能是从参数中推断出来的,也可能是指定的。所以val parent: Hello[Any] = child; parent.test[Any],我们可以将Any指定为test,但这不是String的子类型。
    猜你喜欢
    • 2011-08-10
    • 2017-01-11
    • 1970-01-01
    • 2015-10-02
    • 2014-03-29
    • 2011-05-30
    • 2021-10-06
    • 2011-03-26
    • 1970-01-01
    相关资源
    最近更新 更多