scala – A类有一个类型参数,但B类有一个
最近我偶然遇到了一个奇怪的(对我)编译错误信息。请考虑以下代码:
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]) 我收到以下错误消息:
为什么编译器不能推断类型(虽然我在调用参数中明确说明了这些)?那个类列表有一个类型参数,但是类型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.现在你也可以看到错误信息是错误的:
事实上,如果你在下面的调用中放置一个5859行的断点 checkKindBoundsHK(tparamsHO,tparamsHO) 你可以看到 tparam = {scala.tools.nsc.symtab.Symbols$TypeSymbol@2472}"type B" targ = {scala.tools.nsc.symtab.Types$UniqueTypeRef@2473}"List[X]" 结论:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |