辅助模式用法在不推断适当类型的情况下进行编译

问题描述

考虑以下涉及Aux模式的简单示例:

sealed trait AdtBase

abstract case class Foo(){
  type T <: AdtBase
}

object Foo{
  type Aux[TT] = Foo { type T = TT }
}

abstract case class Bar(){
  type T <: AdtBase
  val foo: Foo.Aux[T]
}

object Bar {
  type Aux[TT] = Bar { type T = TT }

  def apply[TT <: AdtBase](f: Foo.Aux[TT]): Bar = new Bar() {
    override type T = TT
    override val foo: Foo.Aux[T] = f
  }
}

case class Baz(foo: Foo)

def testBaz(baz: Baz) = Bar(baz.foo) //Compiles fine
def testFoo(foo: Foo) = Bar(foo) //Error: Type mismatch

Scastie

我不太了解testBaz为何编译。我也期望类型不匹配。

解决方法

似乎没有深层原因。

自从您明确指定类型参数以来,这两种方法都可以编译

def testBaz(baz: Baz) = Bar[baz.foo.T](baz.foo) //compiles
def testFoo(foo: Foo) = Bar[foo.T](foo)         //compiles

似乎在

def testBaz(baz: Baz) = Bar(baz.foo) //compiles
//def testFoo(foo: Foo) = Bar(foo)   //doesn't compile

在第一种情况下,类型baz.foo.T会被推断,而在第二种情况下,类型foo.T不会被推断

// found   : Foo
// required: Foo.Aux[this.T]

在Scala中,总是有可能无法推断出某些类型参数,而您必须显式地指定它。


也许我找到了可能的原因。

代码

class testFoo2(foo: Foo) {
  // Bar(foo) // doesn't compile
}

不会编译,但是如果您将foo设为val

class testFoo2(val foo: Foo) {
  Bar(foo) // compiles
}

然后就可以了。可能的事情是,当fooval时,它更加“稳定”,在这种情况下,推断路径依赖类型foo.T的过程更加“容易”。

因此testBaztestFoo之间的区别可能是Baz是一个案例类,因此fooval,而在testFoo foo只是一个方法参数,因此不太“稳定”。

类似地,与

相反
trait A[T]
def m[T](a: A[T]) = ???
m(??? : A[_]) // compiles

代码

trait A { type T } 
def m[_T](a: A { type T = _T}) = ??? 
m(??? : A) // doesn't compile

不会编译,但是如果我们提取一个变量

val a: A = ???
m(a) // compiles

然后就可以了。事实是,现在a稳定了,可以推断出类型a.T

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...