简体   繁体   English

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

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

Based on the answers to this question , it appears that placing "forSome" after a component of the type definition is different from placing it at the end of the whole thing. 根据对这个问题的答案,似乎将“ forSome”放置在类型定义的组件之后与将其放置在整个内容的末尾不同。 For instance, it seems there is a difference between the following: 例如,以下内容似乎有所不同:

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

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

The Scala language specification does not seem to say anything about the difference, and I would have imagined that moving the quantifiers to the outside would make no difference. Scala语言规范似乎没有说出任何区别,并且我会想象将量词移到外面不会有任何区别。 If it did make a difference, I would have thought it would be as described in this answer , which basically says Set[X forSome {type X}] allows X to vary between set elements, where Set[X] forSome {type X} does not. 如果确实有所作为,我会以为这将在此答案中进行描述,它基本上说Set [X forSome {type X}]允许X在集合元素之间变化,其中Set [X] forSome {type X}才不是。 However, this does not seem to be the whole story and/or is not correct, because this does not compile: 但是,这似乎不是全部内容,并且/或者是不正确的,因为它不能编译:

trait Bar {
   def test: Set[X] forSome {type X}
}

def test(b: Bar) {
  val set = b.test
  val h = set.head
  set.contains(h)
}

But this does: 但这确实是:

trait Bar {
   def test: Set[X forSome {type X}]
}

def test(b: Bar) {
  val set = b.test
  val h = set.head
  set.contains(h)
}

It seems as if Set[X] forSome {type X} creates a separate abstract type for every usage site in the instantiated class, where Set[X forSome {type X}] creates only one and uses it for the entire class. 似乎Set [X] forSome {type X}为实例化类中的每个使用站点创建了一个单独的抽象类型,其中Set [X forSome {type X}]仅创建了一个抽象类型,并将其用于整个类。 This is the opposite of what I would have expected and seems inconsistent with the answer reference above. 这与我的预期相反,并且似乎与上述答案不一致。

A couple of observations to start with: X forSome { type X } is just a fancy way of writing Any —it's a type we don't know anything about, so it must be at the top of the type hierarchy. 以下是一些观察到的X forSome { type X }X forSome { type X }只是编写Any一种奇特的方式-这是我们一无所知的类型,因此它必须位于类型层次结构的顶部。 If you don't believe me, ask the compiler: 如果您不相信我,请询问编译器:

scala> implicitly[Any =:= X forSome { type X }]
res0: =:=[Any, _] = <function1>

Yep, it agrees. 是的,它同意。

Relatedly, the following won't compile: 相关地,以下内容将无法编译:

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.

Which isn't surprising given what we just learned. 鉴于我们刚刚学到的知识,这不足为奇。 Set is invariant in its type parameter, so a Set[Int] isn't a Set[X forSome { type X }] (ie, a Set[Any] ). Set的type参数是不变的,因此Set[Int]不是Set[X forSome { type X }] (即Set[Any] )。

Given all of this it's also not too surprising that the second test method compiles. 考虑到所有这些,第二种test方法可以编译也就不足为奇了。 When we take the head of b.test , we get an X forSome { type X } (ie, an Any ), and we need an X forSome { type X } (ie, an Any ) for b.test.contains . 当我们使用b.test的头时,我们得到一个X forSome { type X } (即, Any ),并且我们需要一个X forSome { type X } (即Any )用于b.test.contains

So now for the first Bar . 所以现在换第一个Bar Consider the following: 考虑以下:

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

Here we've said xs is a set of some specific type X , but we're immediately going to forget everything about X . 在这里,我们说xs是一组特定类型X的集合,但是我们将立即忘记有关X所有信息。 Note that unlike the xs definition above, this does compile, since we're not saying that xs is a set of anything, just that it's a set of some specific type we don't know (or rather that the compiler doesn't know). 请注意,与上面的xs定义不同,它确实可以编译,因为我们并不是说xs是任何东西的集合,只是它是我们不知道的某种特定类型的集合(或者编译器不知道的) )。

This means that there's absolutely no possible a that will make xs.contains(a) compile. 这意味着,绝对没有任何有可能的a ,这将使xs.contains(a)编译。 Let's try an obvious one: 让我们尝试一个显而易见的方法:

scala> xs.contains(1)
<console>:9: error: type mismatch;
 found   : Int(1)
 required: X
              xs.contains(1)
                          ^

The error message here is interesting— we know that X is actually Int , but the compiler doesn't, since we explicitly asked it to forget that fact with the forSome { type X } . 这里的错误消息很有趣- 我们知道X实际上是Int ,但是编译器不是,因为我们明确要求它使用forSome { type X }来忘记那个事实。 You can see a similarly interesting message by rewriting your test method for the first Bar as follows: 通过重写第一个Bar test方法,您可以看到类似的有趣消息,如下所示:

def test(b: Bar) = b.test.contains(b.test.head)

This also won't compile, with the following message: 这也不会编译,并显示以下消息:

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)
                                             ^

That is, even though we just pulled that b.test.head out of b.test , we still can't apply b.test.contains to it. 也就是说, 即使我们只是将b.test.headb.test ,我们仍然无法对其应用b.test.contains We've told the compiler that the only thing it knows about the item type of b.test is that it exists, so it's not going to keep track of the fact that b.test.head is the kind of thing that we should be able to apply b.test.contains to. 我们已经告诉编译器,它对b.test的项目类型唯一了解的是它的存在,因此它不会跟踪b.test.head是我们应该做的那种事情。能够适用b.test.contains

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

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