繁体   English   中英

Scala泛型语法中“ forSome”子句的位置有何重要意义?

[英]What is the significant of the placement of the “forSome” clause in Scala generics syntax?

根据对这个问题的答案,似乎将“ forSome”放置在类型定义的组件之后与将其放置在整个内容的末尾不同。 例如,以下内容似乎有所不同:

def one: Foo[U >: T] forSome {type U >: T}

def one: Foo[U forSome {type U >: T}]

Scala语言规范似乎没有说出任何区别,并且我会想象将量词移到外面不会有任何区别。 如果确实有所作为,我会以为这将在此答案中进行描述,它基本上说Set [X forSome {type X}]允许X在集合元素之间变化,其中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 }X forSome { type X }只是编写Any一种奇特的方式-这是我们一无所知的类型,因此它必须位于类型层次结构的顶部。 如果您不相信我,请询问编译器:

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的type参数是不变的,因此Set[Int]不是Set[X forSome { type X }] (即Set[Any] )。

考虑到所有这些,第二种test方法可以编译也就不足为奇了。 当我们使用b.test的头时,我们得到一个X forSome { type X } (即, Any ),并且我们需要一个X forSome { type X } (即Any )用于b.test.contains

所以现在换第一个Bar 考虑以下:

scala> val xs: Set[X] forSome { type X } = Set[Int](1, 2, 3)
xs: Set[_] = Set(1, 2, 3)

在这里,我们说xs是一组特定类型X的集合,但是我们将立即忘记有关X所有信息。 请注意,与上面的xs定义不同,它确实可以编译,因为我们并不是说xs是任何东西的集合,只是它是我们不知道的某种特定类型的集合(或者编译器不知道的) )。

这意味着,绝对没有任何有可能的a ,这将使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 test方法,您可以看到类似的有趣消息,如下所示:

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.headb.test ,我们仍然无法对其应用b.test.contains 我们已经告诉编译器,它对b.test的项目类型唯一了解的是它的存在,因此它不会跟踪b.test.head是我们应该做的那种事情。能够适用b.test.contains

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM