Sim*_*n K 5 scala existential-type
根据这个问题的答案,似乎在类型定义的一个组件之后放置"forSome"不同于将它放在整个事件的末尾.例如,似乎以下内容之间存在差异:
def one: Foo[U >: T] forSome {type U >: T}
def one: Foo[U forSome {type U >: T}]
Run Code Online (Sandbox Code Playgroud)
Scala语言规范似乎没有说明差异,我想象将量词转移到外部没有任何区别.如果它确实有所作为,我会认为它将如本答案所述,基本上说Set [X forSome {type X}]允许X在set元素之间变化,其中Set [X] forSome {type X}才不是.但是,这似乎不是整个故事和/或不正确,因为这不编译:
trait Bar {
def test: Set[X] forSome {type X}
}
def test(b: Bar) {
val set = b.test
val h = set.head
set.contains(h)
}
Run Code Online (Sandbox Code Playgroud)
但这样做:
trait Bar {
def test: Set[X forSome {type X}]
}
def test(b: Bar) {
val set = b.test
val h = set.head
set.contains(h)
}
Run Code Online (Sandbox Code Playgroud)
似乎Set [X] forSome {type X}为实例化类中的每个使用站点创建一个单独的抽象类型,其中Set [X forSome {type X}]仅创建一个并将其用于整个类.这与我的预期相反,似乎与上面的答案参考不一致.
首先要注意几点: \xe2\x80\x94X forSome { type X }只是一种奇特的书写方式Any,它是一种我们一无所知的类型,因此它必须位于类型层次结构的顶部。不信你去问编译器:
scala> implicitly[Any =:= X forSome { type X }]\nres0: =:=[Any, _] = <function1>\nRun Code Online (Sandbox Code Playgroud)\n\n是的,它同意。
\n\n相关地,以下内容将无法编译:
\n\nscala> val xs: Set[X forSome { type X }] = Set[Int](1, 2, 3)\n<console>:7: error: type mismatch;\n found : scala.collection.immutable.Set[Int]\n required: Set[X forSome { type X }]\nNote: Int <: X forSome { type X }, but trait Set is invariant in type A.\nRun Code Online (Sandbox Code Playgroud)\n\n鉴于我们刚刚了解到的情况,这并不奇怪。Set其类型参数是不变的,因此 aSet[Int]不是 a Set[X forSome { type X }](即 a Set[Any])。
考虑到所有这些,第二种方法的编译也就不足为奇了test。当我们取 的头部时b.test,我们得到一个X forSome { type X }(即 an Any),并且我们需要 的一个X forSome { type X }(即 an Any)b.test.contains。
现在是第一个Bar。考虑以下:
scala> val xs: Set[X] forSome { type X } = Set[Int](1, 2, 3)\nxs: Set[_] = Set(1, 2, 3)\nRun Code Online (Sandbox Code Playgroud)\n\n这里我们已经说过xs是某种特定类型的集合X,但我们很快就会忘记有关的一切X。请注意,与xs上面的定义不同,这确实可以编译,因为我们并不是说这xs是一组任何东西,只是说它是一组我们不知道的某些特定类型(或者更确切地说,编译器不知道)。
这意味着绝对不可能a进行xs.contains(a)编译。让我们尝试一个显而易见的方法:
scala> xs.contains(1)\n<console>:9: error: type mismatch;\n found : Int(1)\n required: X\n xs.contains(1)\n ^\nRun Code Online (Sandbox Code Playgroud)\n\n这里的错误消息很有趣\xe2\x80\x94,我们知道这X实际上是Int,但编译器不知道,因为我们明确要求它忘记forSome { type X }. test通过重写第一个方法,您可以看到类似有趣的消息,Bar如下所示:
def test(b: Bar) = b.test.contains(b.test.head)\nRun Code Online (Sandbox Code Playgroud)\n\n这也不会编译,并显示以下消息:
\n\nfound : (some other)X(in method test) where type (some other)X(in method test)\nrequired: X(in method test) where type X(in method test)\n def test(b: Bar) = b.test.contains(b.test.head)\n ^\nRun Code Online (Sandbox Code Playgroud)\n\n也就是说,即使我们刚刚将其b.test.head从 中取出b.test,我们仍然无法应用b.test.contains到它。我们已经告诉编译器,它唯一知道的关于项目类型的事情b.test就是它的存在,因此它不会跟踪b.test.head我们应该能够应用的类型这一事实b.test.contains。