从 Seq 到 Set 的转换以及返回到 Seq
直观上,以下内容应该有效:
case class I(i: Int)
val s = Seq(I(1),I(2),I(3))
s.sortBy(_.i) // works
s.toSeq.sortBy(_.i) // works
s.toSet.toSeq.sortBy(_.i) // doesn´t work
为什么它的行为不符合预期?
Intuitively the following should work:
case class I(i: Int)
val s = Seq(I(1),I(2),I(3))
s.sortBy(_.i) // works
s.toSeq.sortBy(_.i) // works
s.toSet.toSeq.sortBy(_.i) // doesn´t work
Why doesn´t it behave as expected?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是混合协变和不变集合的复杂影响。集合是不变的:
Set[A]
。但 Seq 是协变的:Seq[+A]
。现在,假设您希望在 Seq 中有一个toSet
方法。您可以尝试toSet: Set[A]
。但这是行不通的,因为如果A
是B
的子类,那么Seq[A]
应该被视为子类Seq[B]
。但是,Seq[A]
坚持返回一个Set[A]
,它不是 Seq[B]的子类代码>.所以我们的打字被破坏了。另一方面,如果我们指定 toSeq[B >: A]: Set[B] 那么一切都很好:如果我们承诺可以返回任何超类,那么 Seq[A ] 可以返回
Set[B]
以及Set[C]
,其中C
是B< 的超类/代码>。
Seq[B]
承诺返回Set[B]
或一些Set[C]
,所以我们很清楚:该方法Seq[A]
上的方法可以执行Seq[B]
上的方法可以执行的所有操作。但现在看看可怜的打字员所面临的情况:
有一种方法可以解决这个问题,即确定
B
是I
并且相应地键入函数和C
。但这将是一个相当复杂的搜索,并且超出了编译器现在可以处理的范围。因此,它要求您帮助它处理函数的输入类型,以便它知道此时的B
(然后可以将其传播回toSet
)。但是,如果您愿意,您可以在多个级别上帮助它:
或者您可以通过向它证明在选择与早期类型的最佳匹配时不需要考虑后面的类型来帮助它:
This is a complicated impact of mixing covariant and invariant collections. Set is invariant:
Set[A]
. But Seq is covariant:Seq[+A]
. Now, imagine you want to have atoSet
method in your Seq. You might trytoSet: Set[A]
. But this isn't going to work, because ifA
is a subclass ofB
, thenSeq[A]
should be considered as a subclass ofSeq[B]
. However,Seq[A]
insists on returning aSet[A]
which is not a subclass ofSeq[B]
. So our typing is broken.If, on the other hand, we specify
toSeq[B >: A]: Set[B]
then everything is fine: if we promise we can return any superclass, thenSeq[A]
can returnSet[B]
as well asSet[C]
whereC
is a superclass ofB
.Seq[B]
promised to returnSet[B]
or someSet[C]
also, so we're in the clear: the method onSeq[A]
can do everything that the method onSeq[B]
can do.But now look at what the poor typer is faced with:
There is a way to resolve this--namely to decide that
B
isI
and type the function andC
accordingly. But it gets to be a pretty complicated search, and it's more than the compiler can handle right now. So it asks you to help it out with the input type to the function so it knowsB
at that point (and then can propagate it back totoSet
).But you can, if you want, help it out at a number of levels:
or you can help it out by demonstrating to it that it need not consider later types when picking the best match with earlier types:
它看起来像是与类型推断有关,我不太清楚。
但以下两者都可以解决问题:
It looks like about something to do with type inference, I don't know quite well.
But both of following do the trick: