Function.tupled 和占位符语法

11

我在另一个答案中看到了Function.tupled的用法示例:Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)

它是有效的:

scala> Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
<console>:5: warning: method tupled in object Function is deprecated: 
Use `f.tuple` instead
       Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
                                                ^
res0: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 3)

如果我不想使用占位符语法,似乎我可以不用它。

scala> Map(1 -> "one", 2 -> "two") map (x => x._1 -> x._2.length)
res1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 3)

直接使用占位符语法是不起作用的:
scala> Map(1 -> "one", 2 -> "two") map (_._1 -> _._2.length)
<console>:5: error: wrong number of parameters; expected = 1
       Map(1 -> "one", 2 -> "two") map (_._1 -> _._2.length)

Function.tupled是如何工作的?在Function.tupled(_ -> _.length)中似乎有很多事情发生。另外,我该如何使用它以避免出现弃用警告?


@huynhjl Function.tupled的弃用是因为我们认识到一个函数必须知道如何自行进行元组化,而不需要帮助。然而,这在类型推断方面并不起作用。我真的希望他们不会在没有使类型推断器足够聪明以解决这个问题的情况下删除Function.tupled。 - Daniel C. Sobral
1个回答

15

更新:针对这个问题,今天已经取消了函数元组化的弃用。


将一个函数进行元组化,就是将FunctionN[A1, A2, ..., AN, R]适配为Function1[(A1, A2, ..., AN), R]

Function.tuple已被弃用,推荐使用FunctionN#tupled。这可能会导致类型推断器无法推断以下代码中的参数类型(这可能是意外的后果):

scala> Map(1 -> "one", 2 -> "two") map (_ -> _.length).tupled                 
<console>:5: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$minus$greater(x$2.length))
       Map(1 -> "one", 2 -> "two") map (_ -> _.length).tupled
                                        ^
<console>:5: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$minus$greater(x$2.length))
       Map(1 -> "one", 2 -> "two") map (_ -> _.length).tupled

以下任何一个都可以工作:

scala> Map(1 -> "one", 2 -> "two") map { case (a, b)  => a -> b.length }
res8: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 3)

scala> Map(1 -> "one", 2 -> "two") map ((_: Int) -> (_: String).length).tupled           
res9: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 3)

scala> Map(1 -> "one", 2 -> "two") map ((p: (Int, String))  => p._1 -> p._2.length)
res12: scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 3)
我建议您阅读这个最近的问题的答案,以深入了解函数字面值中下划线 '_' 的含义及类型推断的工作原理:在Scala中,使用“_”和使用命名标识符之间有什么区别? 更新: 回答评论,确实如此。
scala> val f = (x:Int, y:String) => x + ": " + y
f: (Int, String) => java.lang.String = <function2>

scala> f.tupled
res0: ((Int, String)) => java.lang.String = <function1>

scala> Map(1 -> "1") map f.tupled
res1: scala.collection.immutable.Iterable[java.lang.String] = List(1: 1)

这需要 Scala 2.8。请注意,如果函数的返回类型是 Tuple2,那么 Map#map 可能会生成另一个 Map,否则生成一个列表,就像上面一样。


谢谢您的回答。让我困惑的是这个代码不起作用:val f = (x:Int, y:String) => x + ": " + y; f.tupled。难道它不应该返回一个可以在(Int,String)元组上工作的f版本吗? - huynhjl
好的,我明白了,这解释了很多问题。我已经重新测试了2.8.0.Beta1版本,并且它按预期工作。之前我尝试使用路径中存在的2.8.0.Beta1-RC5版本。我需要摆脱RC5... - huynhjl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接