加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – A类有一个类型参数,但B类有一个

发布时间:2020-12-16 09:34:19 所属栏目:安全 来源:网络整理
导读:最近我偶然遇到了一个奇怪的(对我)编译错误信息。请考虑以下代码: trait Foo { type Res : Foo type Bar[X : Res]}class MyFoo extends Foo { override type Res = MyFoo override type Bar[X : Res] = List[X]}type FOO[F : Foo,R : Foo,B[_ : R]] = F { t
最近我偶然遇到了一个奇怪的(对我)编译错误信息。请考虑以下代码:

trait Foo {
  type Res <: Foo
  type Bar[X <: Res]
}

class MyFoo extends Foo {
  override type Res = MyFoo
  override type Bar[X <: Res] = List[X]
}

type FOO[F <: Foo,R <: Foo,B[_ <: R]] = F { type Res = R; 
                                              type Bar[X <: R] = B[X] }

def process[F <: Foo,B[_ <: R]](f: FOO[F,R,B]) {}

现在,如果我想调用process方法,我必须明确地写入类型参数:

process[MyFoo,MyFoo,List](new MyFoo) // fine

如果我写:

process(new MyFoo)

要么

process((new MyFoo): FOO[MyFoo,List])

我收到以下错误消息:

inferred kinds of the type arguments (MyFoo,List[X]) do not conform to the expected kinds of the type parameters (type F,type R,type B). List[X]’s type parameters do not match type B’s expected parameters: class List has one type parameter,but type B has one

为什么编译器不能推断类型(虽然我在调用参数中明确说明了这些)?那个类列表有一个类型参数,但是类型B有一个意思吗?有一个,但另一个也有一个,这就是为什么他们不合在一起?

解决方法

如果我们来看Scala编译器,这些来源可以帮助我们了解问题。我从来没有为Scala编译器做过贡献,但是我发现这些源非常可读,我已经对此进行了调查。

负责类型推断的类是scala.tools.nsctypechecker.Infer,您可以通过查看Scala编译器源中的一部分错误来找到它。你会发现以下片段:

/** error if arguments not within bounds. */
    def checkBounds(pos: Position,pre: Type,owner: Symbol,tparams: List[Symbol],targs: List[Type],prefix: String) = {
      //@M validate variances & bounds of targs wrt variances & bounds of tparams
      //@M TODO: better place to check this?
      //@M TODO: errors for getters & setters are reported separately
      val kindErrors = checkKindBounds(tparams,targs,pre,owner)

      if(!kindErrors.isEmpty) {
        error(pos,prefix + "kinds of the type arguments " + targs.mkString("(",",")") +
          " do not conform to the expected kinds of the type parameters "+ tparams.mkString("(",")") + tparams.head.locationString+ "." +
          kindErrors.toList.mkString("n",""))
      }

所以现在的一点是理解为什么checkKindBounds(tparams,targs,pre,owner)返回这些错误。如果你下了方法调用链,你会看到checkKindBounds调用另一个方法

val errors = checkKindBounds0(tparams,owner,true)

你会看到问题是连接到更高种类的检查边界,在5784行,checkKindBoundsHK里面:

if (!sameLength(hkargs,hkparams)) {
        if (arg == AnyClass || arg == NothingClass) (Nil,Nil,Nil) // Any and Nothing are kind-overloaded
        else {error = true; (List((arg,param)),Nil) } // shortcut: always set error,whether explainTypesOrNot
      }

测试没有通过,似乎在我的调试器中:

hkargs$1 = {scala.collection.immutable.Nil$@2541}"List()"
arg$1 = {scala.tools.nsc.symtab.Symbols$ClassSymbol@2689}"class List"
param$1 = {scala.tools.nsc.symtab.Symbols$TypeSymbol@2557}"type B"
paramowner$1 = {scala.tools.nsc.symtab.Symbols$MethodSymbol@2692}"method process"
underHKParams$1 = {scala.collection.immutable.$colon$colon@2688}"List(type R)"
withHKArgs$1 = {scala.collection.immutable.Nil$@2541}"List()"
exceptionResult12 = null
hkparams$1 = {scala.collection.immutable.$colon$colon@2688}"List(type R)"

所以看起来好像有一个更高级的参数,R型,但是没有提供价值。

如果你真的回到checkKindBounds,你会看到在片段之后:

val (arityMismatches,varianceMismatches,stricterBounds) = (
        // NOTE: *not* targ.typeSymbol,which normalizes
        checkKindBoundsHK(tparamsHO,targ.typeSymbolDirect,tparam,tparam.owner,tparam.typeParams,tparamsHO)
      )

arityMatchatches包含一个元组List B.现在你也可以看到错误信息是错误的:

inferred kinds of the type arguments (MyFoo,List[X]) do not
conform to the expected kinds of the type parameters (type F,type
R,type B). List[X]’s type parameters do not match type B’s expected
parameters: class List has one type parameter,but type B has ZERO

事实上,如果你在下面的调用中放置一个5859行的断点

checkKindBoundsHK(tparamsHO,tparamsHO)

你可以看到

tparam = {scala.tools.nsc.symtab.Symbols$TypeSymbol@2472}"type B"
targ = {scala.tools.nsc.symtab.Types$UniqueTypeRef@2473}"List[X]"

结论:

For some reason,when dealing with complex higher-kinded types such as yours,Scala compiler inference is limited. I don’t know where it does come from,maybe you want to send a bug to the compiler team

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读