在 Scala 中的地图上使用收集

发布于 2024-11-19 11:03:43 字数 1952 浏览 3 评论 0原文

我最近偶然发现了这篇帖子,它“引入”了 Scala 集合的 collect 方法。用法很简单:

scala> val ints = List(1, "2", 3) collect { case i: Int => i }
ints: List[Int] = List(1, 3)

现在 ma​​p 基本上是键值对的列表,在 Scala 中用元组表示。所以你可能想尝试这样的事情:

scala> val pairs = Map(1 -> "I", "II" -> 2)
pairs: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)

scala> val intsToStrings = pairs collect { case pair: (Int, String) => pair }

编译器当然会抱怨由于 JVM 的类型擦除模型,所以我们尝试的第一件事是使用存在类型:

scala> val intsToStrings = pairs collect { case pair: (_, _) => pair }
intsToString: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)

虽然代码通过了编译器,并且结果是“正确的”(我们想要对=>我们得到了对)我们仍然没有得到我们真正想要的。第二次尝试如下所示:

scala> val intsToStrings = pairs collect {
     |    case pair: (_, _) if pair._1.isInstanceOf[Int] && pair._2.isInstanceOf[String] => pair
     | }
intsToStrings: scala.collection.immutable.Map[Any,Any] = Map(1 -> I)

好的,我们就快到了:

scala> val realIntsToRealStrings = intsToStrings map {
     |    pair => (pair._1.asInstanceOf[Int], pair._2.asInstanceOf[String])
     | }
realIntsToRealStrings: scala.collection.immutable.Map[Int,String] = Map(1 -> I)

我们做到了,但我们不是仅仅从 (Any,Any) 转换为 (Int,String)实际上复制了每一对并因此创建了一个新对。

现在到了提问部分。正如我提到的“编译器当然会抱怨......”我听起来好像我真的知道我在说什么。我不!我只知道Java从一开始就没有泛型。在某个时候,泛型进入了 Java,但没有进入 JVM。因此编译器会检查所有类型,但是一旦代码运行,JVM 就不关心参数类型。它只看到它是一个 MapList,但看不到它是一个 Map[String, Int]List[Int]

这是我的问题。

通过所有检查、转换和映射,我们成功地将 Map[Any,Any] 传输到 Map[String,Int]。有更好的方法吗?我的意思是类型在那里,JVM 只是看不到它们(就我而言)......

I recently stumbled over this post, which "introduces" the collect method for Scala collections. The usage is straight forward:

scala> val ints = List(1, "2", 3) collect { case i: Int => i }
ints: List[Int] = List(1, 3)

Now maps are basically lists of key-value pairs, which are represented by tuples in Scala. So you might wanna try something like this:

scala> val pairs = Map(1 -> "I", "II" -> 2)
pairs: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)

scala> val intsToStrings = pairs collect { case pair: (Int, String) => pair }

The compiler complains of course due to the type erasure model of the JVM, so the first thing we try is using existential types:

scala> val intsToStrings = pairs collect { case pair: (_, _) => pair }
intsToString: scala.collection.immutable.Map[Any,Any] = Map(1 -> I, II -> 2)

Although the code passed the compiler, and the result is "correct" (we wanted pairs => we got pairs) we still didn't get what we actually wanted. The second attempt looks like this:

scala> val intsToStrings = pairs collect {
     |    case pair: (_, _) if pair._1.isInstanceOf[Int] && pair._2.isInstanceOf[String] => pair
     | }
intsToStrings: scala.collection.immutable.Map[Any,Any] = Map(1 -> I)

Ok, we are almost there:

scala> val realIntsToRealStrings = intsToStrings map {
     |    pair => (pair._1.asInstanceOf[Int], pair._2.asInstanceOf[String])
     | }
realIntsToRealStrings: scala.collection.immutable.Map[Int,String] = Map(1 -> I)

We did it, but instead of only casting from (Any,Any) to (Int,String) we actually copied each pair and thus created a new pair.

Now comes the question part. As I mentioned "The compiler complains of course..." I made it sound like I really know what I'm talking about. I don't! All I know is that Java didn't have generics from the beginning. At some point generics came into Java but not into the JVM. So the compiler checks all the types, but as soon as the code is running, JVM does not care for the parametric type. It only sees that it's a Map or a List but not that it's a Map[String, Int] or List[Int].

So here is my question.

With all the checking, casting and mapping, we managed to transfer a Map[Any,Any] to Map[String,Int]. Is there a better way of doing that? I mean the types are there, JVM just does not see them (as far as I am concerned)...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

束缚m 2024-11-26 11:03:45
pairs collect { case p @ (_: Int, _: String) => p.asInstanceOf[(Int, String)] }

或更简洁,但有一些开销,我认为

pairs collect { case (x: Int, y: String) => (x, y) }
pairs collect { case p @ (_: Int, _: String) => p.asInstanceOf[(Int, String)] }

or more concise, but with some overhead, I think

pairs collect { case (x: Int, y: String) => (x, y) }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文