【问题标题】:How does the scala compiler locate the positions for variance annotationscala编译器如何定位方差注释的位置
【发布时间】:2018-08-26 07:22:45
【问题描述】:

我试图了解编译器如何检查类型参数的位置是协变的还是逆变的。

据我所知,如果类型参数使用 + 进行注释,也就是协变注释,那么任何方法都不能有使用该类/特征的类型参数类型的输入参数。

例如,bar 不能有 T 类型的参数。

class Foo[+T] {
  def bar(param: T): Unit = 
    println("Hello foo bar")
}

因为bar()的参数位置被认为是负数,这意味着该位置的任何类型参数都处于逆变位置。

我很好奇 Scala 编译器如何找到类/特征中的每个位置是正面的、负面的还是中性的。好像有一些规则,比如在某些情况下翻转它的位置,但不能理解清楚。

另外,如果可能的话,我想知道这些规则是如何定义的。例如,在具有协变注释的类中定义的方法的参数,如Foo 类中的bar() 方法,似乎应该具有逆变类类型。为什么?

【问题讨论】:

  • 您能否澄清您的问题:1.“似乎存在一些规则,例如在某些情况下翻转其位置” - 是什么让您这么认为? 2.“在具有协变注释的类中定义的方法的参数......应该具有逆变类类型。为什么?” - 你是在问为什么要引入方差规则,还是其他什么?顺便说一句,其实方法参数可以是逆变类型也可以是非变类型,不一定是逆变的。

标签: scala


【解决方案1】:

我很好奇 Scala 编译器如何找到 阶级/特质是正面的、负面的或中性的。好像有 存在一些规则,例如在某些条件下翻转其位置,但是 看不懂。

Scala compiler 有一个称为解析器的阶段(与大多数编译器一样),它遍历文本并解析出标记。这些标记之一称为方差。如果我们深入细节,有一个名为Parsers.typeParamClauseOpt 的方法负责解析类型参数子句。与您的问题相关的部分是:

def typeParam(ms: Modifiers): TypeDef = {
  var mods = ms | Flags.PARAM
  val start = in.offset
  if (owner.isTypeName && isIdent) {
    if (in.name == raw.PLUS) {
      in.nextToken()
      mods |= Flags.COVARIANT
    } else if (in.name == raw.MINUS) {
      in.nextToken()
      mods |= Flags.CONTRAVARIANT
    }
  }

解析器在类型参数签名中查找+- 符号,并创建一个名为TypeDef 的类,该类描述类型并声明它是协变、逆变或不变的。

另外,如果可能的话,我想知道这些规则是如何定义的。

方差规则是通用的,它们源自名为Category Theory 的数学分支。更具体地说,它们源自Covariant and Contravariant Functors 和两者之间的组合。如果您想了解更多关于这些规则的信息,那将是我要走的路。

此外,Scala 编译器中有一个名为 Variance 的类,如果您想深入了解一下,它在方差规则方面看起来像一个帮助类。

【讨论】:

  • 非常感谢您的解释和编辑!它对我了解内部原理有很大帮助,我从你的回答中学到了很多东西。
猜你喜欢
  • 1970-01-01
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2012-10-22
  • 1970-01-01
相关资源
最近更新 更多