从 Seq 到 Set 的转换以及返回到 Seq

发布于 2024-10-26 18:38:05 字数 229 浏览 1 评论 0原文

直观上,以下内容应该有效:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

走走停停 2024-11-02 18:38:05

这是混合协变和不变集合的复杂影响。集合是不变的:Set[A]。但 Seq 是协变的:Seq[+A]。现在,假设您希望在 Seq 中有一个 toSet 方法。您可以尝试toSet: Set[A]。但这是行不通的,因为如果 AB 的子类,那么 Seq[A] 应该被视为子类Seq[B]。但是,Seq[A] 坚持返回一个 Set[A],它不是 Seq[B]的子类代码>.所以我们的打字被破坏了。

另一方面,如果我们指定 toSeq[B >: A]: Set[B] 那么一切都很好:如果我们承诺可以返回任何超类,那么 Seq[A ] 可以返回 Set[B] 以及 Set[C],其中 CB< 的超类/代码>。 Seq[B] 承诺返回 Set[B] 或一些 Set[C] ,所以我们很清楚:该方法Seq[A] 上的方法可以执行 Seq[B] 上的方法可以执行的所有操作。

但现在看看可怜的打字员所面临的情况:

s.toSet[B >: I]
 .toSeq/* Type B >: I*/
 .sortBy[C](/* some f:B => C */)(/* implicit ordering on C */)

有一种方法可以解决这个问题,即确定 BI 并且相应地键入函数和 C。但这将是一个相当复杂的搜索,并且超出了编译器现在可以处理的范围。因此,它要求您帮助它处理函数的输入类型,以便它知道此时的 B(然后可以将其传播回 toSet)。

但是,如果您愿意,您可以在多个级别上帮助它:

s.toSet[I].toSeq.sortBy(_.i)
s.toSet.toSeq.sortBy[Int](_.i)

或者您可以通过向它证明在选择与早期类型的最佳匹配时不需要考虑后面的类型来帮助它:

{ val temp = s.toSet; temp }.toSeq.sortBy(_.i)
s.toSet match { case x => x.toSeq.sortBy(_.i) }

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 a toSet method in your Seq. You might try toSet: Set[A]. But this isn't going to work, because if A is a subclass of B, then Seq[A] should be considered as a subclass of Seq[B]. However, Seq[A] insists on returning a Set[A] which is not a subclass of Seq[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, then Seq[A] can return Set[B] as well as Set[C] where C is a superclass of B. Seq[B] promised to return Set[B] or some Set[C] also, so we're in the clear: the method on Seq[A] can do everything that the method on Seq[B] can do.

But now look at what the poor typer is faced with:

s.toSet[B >: I]
 .toSeq/* Type B >: I*/
 .sortBy[C](/* some f:B => C */)(/* implicit ordering on C */)

There is a way to resolve this--namely to decide that B is I and type the function and C 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 knows B at that point (and then can propagate it back to toSet).

But you can, if you want, help it out at a number of levels:

s.toSet[I].toSeq.sortBy(_.i)
s.toSet.toSeq.sortBy[Int](_.i)

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:

{ val temp = s.toSet; temp }.toSeq.sortBy(_.i)
s.toSet match { case x => x.toSeq.sortBy(_.i) }
睫毛上残留的泪 2024-11-02 18:38:05

它看起来像是与类型推断有关,我不太清楚。

但以下两者都可以解决问题:

s.toSet.toSeq.asInstanceOf[Seq[I]].sortBy(_.i)
s.toSet.toSeq.sortWith(_.i < _.i)

It looks like about something to do with type inference, I don't know quite well.

But both of following do the trick:

s.toSet.toSeq.asInstanceOf[Seq[I]].sortBy(_.i)
s.toSet.toSeq.sortWith(_.i < _.i)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文