这两个Scala定义有什么区别

时间:2015-10-12 05:27:17

标签: scala

我在Scala中有以下2个定义,这给了我相同的结果。但它彼此有点不同。

def sum(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)     //> sum: (f: Int => Int)(a: Int, b: Int)Int

sum(x => x*x)(1,2)   //> res3: Int = 5  

第二个是

def sum(f: Int => Int,a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f,a + 1, b)      //> sum2: (f: Int => Int, a: Int, b: Int)Int

sum(x => x*x,1,2)                               //> res4: Int = 5

我看到的唯一不同之处是sum(f: Int => Int,a: Int, b: Int)sum(f: Int => Int)(a: Int, b: Int)。在后一种情况下,函数参数和值参数是分开的。

这是什么行为。这真的是相同还是它们之间有不同?

2 个答案:

答案 0 :(得分:5)

关于你使用它们的方式,它们几乎完全相同。但是第一个版本通常具有一些额外的灵活性(和实用性)。

例如

val g = sum(x => x*x) _  //g has type (Int, Int) => Int
println(g(2, 3))         //prints 13

这称为currying。您可以使用两个以上的参数列表来执行此操作,例如

def foo(b: Boolean)(i: Int)(s: String)(d: Double): Int = ...
val g = foo(true) _  //g has type Int => (String => (Double => Int))
val h = g(3) _       //h has type String => (Double => Int)
val r = h("asdf") _  //r has type Double => Int

根据上下文,有时可以不使用下划线,例如

val r: Int => Double = foo(true)(3)("asdf")

多个参数列表也用于隐式参数,以及Scala编译器需要一些类型推理帮助时。当与call-by-name参数一起使用时,它们也可以方便地通过库创建伪造的语法或控制结构,例如。

def repeat(n: Int)(body: => Unit) { 
  var i = n
  while (i > 0) { i -= 1; body }
}

var counter = 0
repeat(10) {                  //This method call (repeat) looks a bit like a part                   
  println(s"Hello: $counter") //of the language due to call-by-name argument, 
  counter += 1                //multiple parameter lists, use of curly braces, etc.
} 

结果

您好:1 你好:2 。 。 。 你好9

答案 1 :(得分:1)

是的,它们是一样的。您可以使用多个参数块,原因有多种,其中没有一个适用于此:

  1. 为了帮助使用泛型方法键入推断(例如,如果您有def foo[A](a: A, f: A => A)并调用foo(1, _ + 1),您可能希望编译器理解AInt。但在确定_ + 1的类型之前,它无法做到这一点。如果您使用def foo[A](a: A)(f: A => A)代替它,它就可以工作。

  2. 在默认值中使用以前的参数。例如。 def foo(x: Int, y: Int = x)无法编译,def foo(x: Int)(y: Int = x)可以。{/ p>

  3. 函数参数本身可以用括号写成大括号:

    def sum(a: Int, b: Int)(f: Int => Int): Int
    
    sum(1, 2) { x => x*x }
    
  4. 最后一个块可以包含implicit parameters