9

对存在类型有点困惑。

这对我有用:

def valueOf(c: Class[_], name: String) {
  type C = Class[T] forSome {type T <: Enum[T]}
  Enum.valueOf(c.asInstanceOf[C], name)
} 

但这不会:

def valueOf(c: Class[_], name: String) {
  type T = T forSome {type T <: Enum[T]}
  Enum.valueOf(c.asInstanceOf[Class[T]], name)
}

在我看来,这两种表达方式都相当于:

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name)

但 Scala 说这只是我的想法:

inferred type arguments [T] do not conform to method valueOf's type parameter bounds [T <: Enum[T]]
         Enum.valueOf(c.asInstanceOf[Class[T]], name)
              ^
4

1 回答 1

6

考虑以下两个表达式之间的区别:

Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)

和:

Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)

现在考虑在每种情况下如何推断T类型参数。valueOf在第一种情况下,我们有一个X我们知道是 的子类型的Enum[X],我们都准备好了。另一方面,在第二种情况下,T必须是X forSome { type X <: Enum[X] },而且至关重要的是,这种类型不是 的子类型Enum[X forSome { type X <: Enum[X] }],所以我们没有满足 上的约束T

问题是您的第二个示例等效于后者。


Enum作为一个脚注,如果它的类型参数是协变的,这将工作得很好。采取以下简化示例:

trait Foo[A]
trait Bar[A]

def foo[A <: Bar[A]](f: Foo[A]) = f

def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???

现在foo(x)将编译,但foo(y)不会,就像在您的代码中一样。但是稍微改变Bar一下:

trait Foo[A]
trait Bar[+A]

def foo[A <: Bar[A]](f: Foo[A]) = f

def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???

现在它们都将编译。我猜这与我们对您的两个示例等效的直觉如此强烈的原因有关。


作为另一个脚注(响应gzmo下面的评论),请考虑以下内容:

scala> trait Foo[A <: Foo[A]]
defined trait Foo

scala> class MyFoo extends Foo[MyFoo]
defined class MyFoo

scala> val myFoo = new MyFoo
myFoo: MyFoo = MyFoo@3ee536d

scala> myFoo: (X forSome { type X <: Foo[X] })
res0: X forSome { type X <: Foo[X] } = MyFoo@3ee536d

scala> myFoo: Foo[MyFoo]
res1: Foo[MyFoo] = MyFoo@3ee536d

让我们假设这X forSome { type X <: Foo[X] } 一个子类型Foo[X forSome { type X <: Foo[X] }](暂时忽略后者甚至不是有效类型的事实)。然后我们就可以写出以下内容:

myFoo: Foo[X forSome { type X <: Foo[X] }]

但是Foo是不变的,所以如果我们有一些东西是 和 的实例Foo[A]Foo[B]那么它一定是A =:= B。但绝对不是这样的MyFoo =:= (X forSome { type X <: Foo[X] })。不确定所有这些是否会减少混乱,但这就是我如何说服自己编译器知道它在这里做什么的方式。

于 2013-08-23T13:09:58.510 回答