【问题标题】:scala tuple unpackingscala 元组解包
【发布时间】:2010-08-25 16:15:31
【问题描述】:

我知道这个问题已经多次以不同的方式提出。但我仍然不清楚。有没有办法实现以下目标。

def foo(a:Int, b:Int) = {}

foo(a,b) //right way to invoke foo

foo(getParams) // is there a way to get this working without explicitly unpacking the tuple??

def getParams = {
   //Some calculations
   (a,b)  //where a & b are Int
}

【问题讨论】:

标签: scala parameters tuples


【解决方案1】:

这是一个两步程序。先把 foo 变成一个函数,然后在它上面调用 tupled 使它成为一个元组的函数。

(foo _).tupled(getParams)

【讨论】:

  • 如果 Scala 一开始就将参数视为元组,会不会更简洁?
  • 是的,如果 Scala 将它对元组和参数列表的处理统一起来,它会干净得多。据我所知,有很多不明显的边缘情况需要仔细处理才能实现。据我所知,元组和参数列表的统一目前不在 Scala 路线图上。
  • 补充一下,如果 foo 是伴生对象的工厂方法,可以使用 (Foo.apply _).tupled(getParams)
【解决方案2】:

@dave-griffith 已经死了。

您也可以调用:

Function.tupled(foo _)

如果您想进入“比我要求的信息多得多”的领域,还有一些内置于部分应用函数(以及 Function)中的方法用于柯里化。一些输入/输出示例:

scala> def foo(x: Int, y: Double) = x * y
foo: (x: Int,y: Double)Double

scala> foo _
res0: (Int, Double) => Double = <function2>

scala> foo _ tupled
res1: ((Int, Double)) => Double = <function1>

scala> foo _ curried
res2: (Int) => (Double) => Double = <function1>

scala> Function.tupled(foo _)
res3: ((Int, Double)) => Double = <function1>

// Function.curried is deprecated
scala> Function.curried(foo _)
warning: there were deprecation warnings; re-run with -deprecation for details
res6: (Int) => (Double) => Double = <function1>

其中 curried 版本使用多个参数列表调用:

scala> val c = foo _ curried
c: (Int) => (Double) => Double = <function1>

scala> c(5)
res13: (Double) => Double = <function1>

scala> c(5)(10)
res14: Double = 50.0

最后,如果需要,您还可以取消咖喱/取消元组。 Function 已为此内置:

scala> val f = foo _ tupled
f: ((Int, Double)) => Double = <function1>

scala> val c = foo _ curried
c: (Int) => (Double) => Double = <function1>

scala> Function.uncurried(c)
res9: (Int, Double) => Double = <function2>

scala> Function.untupled(f)
res12: (Int, Double) => Double = <function2>

【讨论】:

    【解决方案3】:

    Function.tupled(foo _)(getParams) 或 Dave 建议的那个。

    编辑:

    回复您的评论:

    如果 foo 恰好是 某个类的构造函数?

    这样的话,这个技巧就行不通了。

    您可以在类的伴随对象中编写工厂方法,然后使用上述技术之一获得其apply 方法的元组版本。

    scala> class Person(firstName: String, lastName: String) {
         |   override def toString = firstName + " " + lastName
         | }
    defined class Person
    
    scala> object Person {
         |   def apply(firstName: String, lastName: String) = new Person(firstName, lastName)
         | }
    defined module Person
    
    scala> (Person.apply _).tupled(("Rahul", "G"))
    res17: Person = Rahul G
    

    使用case classes,您可以免费获得一个带有apply 方法的伴生对象,因此这种技术与case classes 一起使用更方便。

    scala> case class Person(firstName: String, lastName: String)
    defined class Person
    
    scala> Person.tupled(("Rahul", "G"))
    res18: Person = Person(Rahul,G)
    

    我知道这有很多代码重复,但是唉……我们还没有宏! ;)

    【讨论】:

    • 在这里的最后一个示例中,您可以稍微减少一点……案例类的伴随对象总是扩展适当的 FunctionN 特征。所以最后一行可能是Person.tupled(("Rahul", "G")) 在手写伴生对象中也很方便。
    【解决方案4】:

    我很欣赏其他一些更接近您要求的答案,但我发现当前项目添加另一个将元组参数转换为拆分参数的函数更容易:

    def originalFunc(a: A, b: B): C = ...
    def wrapperFunc(ab: (A, B)): C = (originalFunc _).tupled(ab)
    

    【讨论】:

      【解决方案5】:

      现在,您可以像这样实现 foo 并使其接受 Tuple2 类的参数。

      def foo(t: Tuple2[Int, Int]) = {
        println("Hello " + t._1 + t._2)
        "Makes no sense but ok!"
      }
      
      def getParams = {
        //Some calculations
        val a = 1;
        val b = 2;
        (a, b) //where a & b are Int
      }
      
      // So you can do this!
      foo(getParams)
      // With that said, you can also do this!
      foo(1, 3)
      

      【讨论】:

        猜你喜欢
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 2015-12-15
        • 1970-01-01
        • 2014-08-03
        • 1970-01-01
        • 2021-08-05
        • 1970-01-01
        相关资源
        最近更新 更多