Scala中的Existensial类型

dk1*_*k14 9 enums types scala existential-type

关于存在主义类型的一点混乱.

这对我有用:

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

但这不是:

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

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

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name)
Run Code Online (Sandbox Code Playgroud)

但斯卡拉说,这只是我的想法:

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

Tra*_*own 6

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

Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)
Run Code Online (Sandbox Code Playgroud)

和:

Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)
Run Code Online (Sandbox Code Playgroud)

现在想想怎样类型参数TvalueOf将在每种情况来推断.在第一种情况下,我们得到了一个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] }] = ???
Run Code Online (Sandbox Code Playgroud)

现在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] }] = ???
Run Code Online (Sandbox Code Playgroud)

现在他们都会编译.我猜这与我们对你的两个例子相当的强烈直觉的原因有关.


作为另一个脚注(回应下面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
Run Code Online (Sandbox Code Playgroud)

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

myFoo: Foo[X forSome { type X <: Foo[X] }]
Run Code Online (Sandbox Code Playgroud)

但是Foo是不变的,所以如果我们有一些东西,是两个实例Foo[A]Foo[B],那么它必须是该案件A =:= B.但绝对不是这样的MyFoo =:= (X forSome { type X <: Foo[X] }).不确定所有这些都不会让人感到困惑,但我确信编译器知道它在这里做了什么.