11

我在让 Scala 从类型投影中推断出正确的类型时遇到了一些麻烦。

考虑以下:

trait Foo {
  type X
}

trait Bar extends Foo {
  type X = String
}

def baz[F <: Foo](x: F#X): Unit = ???

然后以下编译正常:

val x: Foo#X = ???    
baz(x)

但以下内容无法编译:

val x: Bar#X = ???    
baz(x)

Scala 看到 的“基础类型 String” x,但丢失xBar#X. 如果我注释类型,它工作正常:

baz[Bar](x)

有没有办法让 Scala 推断出正确的类型参数baz
如果不是,那么使它不可能的一般答案是什么?

4

2 回答 2

2

程序通过在上下文中添加这个隐式转换来编译:

implicit def f(x: Bar#X): Foo#X = x

由于这种隐式转换对于 any 都是正确的F <: Foo,我想知道为什么编译器不自己这样做。

于 2013-02-22T04:25:16.107 回答
1

你也可以:

trait Foo {
    type X
}
trait Bar extends Foo {
    type X = String
}
class BarImpl extends Bar{
  def getX:X="hi"
}
def baz[F <: Foo, T <: F#X](clz:F, x: T): Unit = { println("baz worked!")}
val bi = new BarImpl
val x: Bar#X = bi.getX
baz(bi,x)

但:

def baz2[F <: Foo, T <: F#X](x: T): Unit = { println("baz2 failed!")}
baz2(x)

失败:

test.scala:22: error: inferred type arguments [Nothing,java.lang.String] do not conform to method baz2's type parameter bounds [F <: this.Foo,T <: F#X]
baz2(x)
^
one error found

我认为基本上, F <: Foo 告诉编译器 F 必须是 Foo 的子类型,但是当它得到一个 X 时,它不知道你的特定X 来自哪个类。您的 X 只是一个字符串,不保留指向 Bar 的信息。

注意:

def baz3[F<: Foo](x : F#X) = {println("baz3 worked!")}
baz3[Bar]("hi")

也有效。你定义了一个 val x:Bar#X=??? 就是那个意思???仅限于 Bar#X 在编译时可能发生的任何事情......编译器知道 Bar#X 是字符串,因此 x 的类型只是一个字符串,与任何其他字符串没有区别。

于 2013-02-08T21:59:17.937 回答