使用多个函数参数列表有什么好处?

时间:2013-08-08 01:02:55

标签: scala

scala> def a(i:Int)(j:Int) = i * j
a: (i: Int)(j: Int)Int

scala> def b(i:Int, j:Int) = i * j
b: (i: Int, j: Int)Int

这两个定义非常相似,它们(在我看来)做同样的事情。

除了定义一个接收隐式参数或代码块作为参数的函数外,还有什么理由使用第一个定义样式吗?

3 个答案:

答案 0 :(得分:6)

这是我随时编制的列表:

多个参数列表

1)类型分辨率

class ResourceManager {
  type Resource

  def open: Resource = ???
}

class ResourceManagerTest {
  // Does not compile: def test1(rm: ResourceManager, r: rm.Resource) = ???

  // Compiles: This way the type can be resolved
  def test2(rm: ResourceManager)(r: rm.Resource) = ???
}

2)类型推断前面的参数可以“锁定”类型参数以供以后的参数使用(感谢Myserious Dan)

  def foo1[A](x: A, f: A => Int) = ???

  def foo2[A](x: A)(f: A => Int) = ???

  def foo1foo2Demo() {
    // This will always demand a type annotation on any anonymous function
    // you pass in:
    foo1(1, (i: Int) => i * i)

    // Does not compile: foo1(1, i => i * i)

    // Type not required
    foo2(2)(i => i * i)
  }

3)类似语法的语言扩展

object MultipleArgumentListsDemo {
  // This style of function definition allows syntax-like language extensions
  @tailrec
  def myWhile(conditional: => Boolean)(f: => Unit) {
    if (conditional) {
      f
      myWhile(conditional)(f)
    }
  }

  def myWhileDemo() {
    var count = 0
    myWhile(count < 5) {
      count += 1
      println(count)
    }
  }

4)同时拥有隐式和非隐式参数,因为implicit是整个参数列表的修饰符:

  def f[A](x: A)(implicit mf: Manifest[A]) {
  }

5)来自一个参数列表的参数值可用于计算另一个参数列表中的默认值,但不能用于同一个参数列表。

  def g(x: Int)(y: Int = x * 2) = {
    x + y
  }

6)多个重复的参数列表(“varargs”)

  def h(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum

7)部分申请

  def i() {
    val foop = h(1, 2, 3)(4, 5, 6, 7, 9) _
    println(foop(Seq(10, 11)))
 }

由于我在编制该列表的过程中没有跟踪我的来源:有可能从其他地方复制了一些或所有示例(其他问题在SO上),所以请删掉一个注释,我将添加引用至于它来自何处。

答案 1 :(得分:3)

以这种方式“currying”功能的主要原因是启用部分应用:

scala> val c = a(5) _
c: Int => Int = <function1>

这里c是一个函数,它接受一个int并返回将该int与5相乘的结果。可能是你在一个方法中设置c,并将它传递给另一个期望函数占用一个Int的方法参数。在这种情况下有点微不足道,但对于一系列用途非常灵活。

答案 2 :(得分:1)

除了支持currying之外,它还有助于类型推断:如果一切都在一个参数列表中,有时编译器无法推断出正确的类型,但是如果你拆分依赖于其他参数绑定的部分,有用。一个典型的例子是foldLeft:尝试用一个参数列表实现它,然后在某些情况下编译器需要类型注释。