在Scala泛型语法中放置“forSome”子句有什么重要意义?
基于
this question的答案,似乎在类型定义的组件之后放置“forSome”与将其放在整个事件的末尾不同.例如,似乎以下内容之间存在差异:
def one: Foo[U >: T] forSome {type U >: T} def one: Foo[U forSome {type U >: T}] Scala语言规范似乎没有说明差异,我想象将量词转移到外部没有任何区别.如果它确实有所作为,我认为它将如this answer所述,基本上说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) } 但这样做: trait Bar { def test: Set[X forSome {type X}] } def test(b: Bar) { val set = b.test val h = set.head set.contains(h) } 似乎Set [X] forSome {type X}为实例化类中的每个使用站点创建一个单独的抽象类型,其中Set [X forSome {type X}]仅创建一个并将其用于整个类.这与我的预期相反,似乎与上面的答案参考不一致. 解决方法
一些观察开始:X forSome {type X}只是一种奇特的编写方式Any-it是一种我们什么都不知道的类型,因此它必须位于类型层次结构的顶部.如果你不相信我,请问编译器:
scala> implicitly[Any =:= X forSome { type X }] res0: =:=[Any,_] = <function1> 是的,它同意. 相关地,以下内容不会编译: scala> val xs: Set[X forSome { type X }] = Set[Int](1,2,3) <console>:7: error: type mismatch; found : scala.collection.immutable.Set[Int] required: Set[X forSome { type X }] Note: Int <: X forSome { type X },but trait Set is invariant in type A. 鉴于我们刚刚学到的东西,这并不奇怪. Set在其类型参数中是不变的,因此Set [Int]不是Set [X forSome {type X}](即,Set [Any]). 考虑到所有这一点,第二种测试方法编译也就不足为奇了.当我们取b.test的头部时,我们得到一个X forSome {type X}(即Any),我们需要一个X forSome {type X}(即Any)用于b.test.contains. 所以现在为第一个吧.考虑以下: scala> val xs: Set[X] forSome { type X } = Set[Int](1,3) xs: Set[_] = Set(1,3) 这里我们说过xs是一些特定类型X的集合,但我们会立即忘记关于X的所有内容.请注意,与上面的xs定义不同,这会编译,因为我们并不是说xs是一个集合任何事情,只是它是一组我们不知道的特定类型(或者说编译器不知道). 这意味着绝对没有可能使xs.contains(a)编译.让我们尝试一个明显的: scala> xs.contains(1) <console>:9: error: type mismatch; found : Int(1) required: X xs.contains(1) ^ 这里的错误消息很有趣 – 我们知道X实际上是Int,但编译器没有,因为我们明确要求它忘记了forSome {type X}的事实.您可以通过重写第一个Bar的测试方法来查看类似的有趣消息,如下所示: def test(b: Bar) = b.test.contains(b.test.head) 这也将无法编译,并显示以下消息: found : (some other)X(in method test) where type (some other)X(in method test) required: X(in method test) where type X(in method test) def test(b: Bar) = b.test.contains(b.test.head) ^ 也就是说,即使我们将b.test.head从b.test中拉出来,我们仍然无法将b.test.contains应用于它.我们已经告诉编译器,它唯一知道的关于b.test的项类型是它存在,所以它不会跟踪b.test.head是我们应该做的事情的事实能够将b.test.contains应用于. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |