本文介绍了Scala中的Existensic类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



这对我有用:

  类型X (稍后忽略后者甚至不是有效类型的事实)。然后我们可以写下列内容:

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

但是 Foo 是不变的,所以如果我们有一些东西是 Foo [A] 和 Foo [B] 的实例,那么它必须情况是 A =:= B 。但是绝对不是这样的情况: MyFoo =:=(X forSome {type X< ;:Foo [X]})。不确定所有这些都不那么令人困惑,但这是怎么说服自己,编译器知道它在做什么。


Little confusing about existential types.

This works for me:

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

but this does not:

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

In my mind both expressions are equivalent to:

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

But Scala says that it's in my mind only:

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

Consider the difference between the following two expressions:

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

And:

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

Now think about how the type parameter T of valueOf will be inferred in each of these cases. In the first case, we've got an X that we know is a subtype of Enum[X], and we're all set. In the second case, on the other hand, T would have to be X forSome { type X <: Enum[X] }, and crucially this type is not a subtype of Enum[X forSome { type X <: Enum[X] }], so we haven't satisfied the constraint on T.

The problem is that your second example is equivalent to the latter.


As a footnote, this would work just fine if Enum were covariant in its type parameter. Take the following simplified example:

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] }] = ???

Now foo(x) will compile, but foo(y) won't, just as in your code. But change Bar a bit:

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] }] = ???

Now they'll both compile. I'd guess that this has something to do with the reason that we have such strong intuitions about your two examples being equivalent.


As another footnote (in response to gzmo's comment below), consider the following:

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

Let's suppose that X forSome { type X <: Foo[X] } were a subtype of Foo[X forSome { type X <: Foo[X] }] (ignoring for a moment the fact that the latter isn't even a valid type). Then we'd be able to write the following:

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

But Foo is invariant, so if we have some thing that's an instance of both Foo[A] and Foo[B], then it must be the case that A =:= B. But it's definitely not the case that MyFoo =:= (X forSome { type X <: Foo[X] }). Not sure all of that is any less confusing, but it's how I convinced myself that the compiler knows what it's doing here.

这篇关于Scala中的Existensic类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 05:20