【问题标题】:Map a variable of type of Pair -- impossible映射 Pair 类型的变量——不可能
【发布时间】:2013-07-01 23:34:52
【问题描述】:

这对我来说似乎不合逻辑:

scala> val a = Map((1, "111"), (2, "222"))
a: scala.collection.immutable.Map[Int,String] = Map(1 -> 111, 2 -> 222)

scala> val b = a.map((key, value) => value)
<console>:8: error: wrong number of parameters; expected = 1
       val b = a.map((key, value) => value)
                                  ^
scala> val c = a.map(x => x._2)
c: scala.collection.immutable.Iterable[String] = List(111, 222)

我知道我可以说val d = a.map({ case(key, value) =&gt; value })

但是为什么不能说 a.map((key, value) =&gt; value) 呢? 只有一个参数,类型为 Tuple2[Int, String]Pair of Int, Stringa.map((key, value) =&gt; value)a.map(x =&gt; x._2) 有什么区别?

更新

val myTuple2 = (1, 2) -- 这是一个变量,对吗?

for ( (k, v) &lt;- a ) yield v -- (k, v) 也只是一个变量,对吗?

map((key, value) =&gt; value) -- 2 个变量。很奇怪。

那么如何在不使用case 的情况下在map 中指定Tuple2(或任何其他类型)类型的变量?

更新 2:

这有什么问题?

Map((1, "111"), (2, "222")).map( ((x,y):Tuple2[Int, String]) =&gt; y)——错误

Map((1, "111"), (2, "222")).map( ((x):Tuple2[Int, String]) =&gt; x._2) -- 好的

【问题讨论】:

  • 只有一个Tuple2[Int, String] 类型的变量。 map 有签名def map[B](f: (A) ⇒ B): Map[B]——它接受一个函数,该函数接受 A 类型的 one 变量并产生 B 类型的 one 输出变量(x =&gt; x._2 就是这样的一个例子函数,而(key, value) =&gt; value 不是)
  • @om-nom-nom, (key, value) -- 是 Tuple2 类型的一个变量。
  • 如果那是真的List(1,2,3,4).reduce((x,y) =&gt; x + y) 就不可能了
  • @MariusKavansky,om-nom-nom 100% 正确。相信我。
  • 那么为什么不使用 a.map { x =&gt; val (key, value) = x; value } 来解构它们(正如 om-nom-nom 所说)。是的,它比您希望的更冗长,但它具有相同的意图。另外,我很好奇为什么“案例”是不可能的,因为它似乎符合人们的预期。

标签: scala


【解决方案1】:

好吧,你还是不信。在这种情况下,回退到真相的来源是很合理的(嗯,有点):The Holy Specification(又名,Scala 语言规范)。

因此,在匿名函数中,参数是单独处理的,而不是作为一个完整的元组带(而且它非常聪明,否则,您将如何调用具有 2、... n 个参数的匿名函数?)。

同时

val x = (1, 2) 

是 Tiple2[Int,Int] 类型的单个项目(如果您有兴趣,也可以找到相应的规范部分)。

for ( (k, v) <- a ) yield v

在这种情况下,您将一个变量解压缩为两个变量。类似于

val x = (1, 2) // one variable -- tuple
val (y,z) = x  // two integer variables unpacked from one

有些人称之为解构赋值,这是模式匹配的一种特殊情况。而且您已经提供了另一个实际的模式匹配示例:

a.map({ case(key, value) => value })

我们可以将其理解为 map 接受由部分函数字面量生成的函数,从而可以使用模式匹配

【讨论】:

  • 那么如何在不使用大小写的情况下在 map 中指定 Tuple2 类型(或任何其他类型)的变量?
  • @MariusKavansky 目前没有其他时髦的方法(如果我没听错的话:您希望在不使用 case 和显式寻址的情况下为 .map 提供类似for ((k,v) &lt;- m) yield v 的语法)。我看过一个关于 ML 的帖子,但它充满了矛盾和极端情况,所以我怀疑你能否在可预见的将来做到这一点。
  • @MariusKavansky 我找不到我说过的话题,但是there is one another
【解决方案2】:

你基本上是在问同样的问题:

Scala - can a lambda parameter match a tuple?

您已经列出了他们在那里列出的大部分选项,包括使用 PartialFunction 的公认答案。

但是,由于您在 map 函数中使用 lambda,因此您可以改用 for 理解:

for ( (k, v) <- a ) yield v

或者,您可以使用Function2.tupled 方法来修复您的 lambda 类型:

scala> val a = Map((1, "111"), (2, "222"))
a: scala.collection.immutable.Map[Int,String] = Map(1 -> 111, 2 -> 222)
scala> a.map( ((k:Int,v:String) => v).tupled )
res1: scala.collection.immutable.Iterable[String] = List(111, 222)

要使用上面的 om-nom-nom 在您的线程中回答您的问题,请查看以下输出:

scala> ( (x:Int,y:String) => y ).getClass.getSuperclass
res0: Class[?0] forSome { type ?0 >: ?0; type ?0 <: (Int, String) => String } = class scala.runtime.AbstractFunction2

注意匿名函数(x:Int,y:String) =&gt; y的超类是Function2[Int, String, String],而不是Function1[(Int, String), String]

【讨论】:

  • 这不是我要问的。
  • @MariusKavansky - 实际上,这正是你要问的——你只是没有意识到!你应该听 om-nom-nom。
  • @MariusKavansky - 是的,这是一个更好的问题 - 答案在我链接到的线程中。您必须进行某种模式匹配/解构。查看 om-nom-nom 的回答,了解 Scala 语言规范如何说 (x,y)=&gt;y 中的 (x,y)parameter list 而不是 tuple
【解决方案3】:

您可以使用模式匹配(或部分函数,​​在本例中是相同的),注意尖括号:

val b = a.map{ case (key, value) => value }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2017-03-21
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多