【问题标题】:Cannot infer contravariant Nothing type parameter无法推断逆变 Nothing 类型参数
【发布时间】:2017-10-09 09:06:31
【问题描述】:

考虑以下 sn-p:

trait X[-T]
object Y extends X[Nothing]
def a[T](x: X[T]): X[T] = x
a(Y)

上述 (2.12.3) 的编译失败:

type mismatch;
found   : Y.type
required: X[T]
   a(Y)
     ^

如果满足以下条件,则编译良好:

  • 使用了与Nothing 不同的类型(例如object Y extends X[String]
  • 方法a 没有在其返回类型中使用T(例如def a[T](x: X[T]): Unit = {}
  • a 的类型参数是明确给出的(即a[Nothing](Y)
  • T 是协变的,而不是逆变的(如果它是不变的,也会失败)

这是Nothing 的编译器中的一些特殊情况吗?

作为一个“有趣”的解决方法,以下似乎可以正常工作:

trait X[-T]
object Y extends X[Nothing]
def a[T, U <: T](x: X[T]): X[U] = x
a(Y)

【问题讨论】:

    标签: scala scala-compiler


    【解决方案1】:

    我会试着逐行解释代码

    第 1 行:trait X[-T] -> 特征 X 在类型 T 中是逆变的。因此您可以将 X[T] 类型的任何变量替换为其子类型。在逆变类型的情况下,如果 B 是 A 的子类型,则 Z[A] 是 Z[B] 的子类型。

    第 2 行:object Y extends X[Nothing] -> 对象 Y 的类型为 X[Nothing]。请注意,Nothing 是所有其他类型的子类型。

    第 3 行:def a[T](x: X[T]): X[T] = x -> 定义一个接受 X[T] 类型参数的表达式。因为特征 X 在类型 T 中是逆变的,所以您还可以传递 X[T] 的子类型,即 X[N] 使得 T 是 N 的子类型

    第 4 行:a(Y) -> 使用 X[Nothing] 类型的参数调用表达式“a”。由于编译器不知道 'a' 的参数类型,它无法确定 X[Nothing] 是否是 X[T] 的子类型。有多种方法可以解决这个问题

    Solution 1: `a[Nothing]` -> explicitly defining the type
    
    Solution 2: `tait X[+T]` -> make X covariant in type T. In this case Z[A] is subtype of Z[B] if A is subtype of B. This will work because Nothing is subtype of any other type
    

    【讨论】:

    • 感谢您的回答,但为什么使用String 而不是Nothing 会使示例编译?或者为什么解决方法有效?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    相关资源
    最近更新 更多