我在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)
。在后一种情况下,函数参数和值参数是分开的。
这是什么行为。这真的是相同还是它们之间有不同?
答案 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)
是的,它们是一样的。您可以使用多个参数块,原因有多种,其中没有一个适用于此:
为了帮助使用泛型方法键入推断(例如,如果您有def foo[A](a: A, f: A => A)
并调用foo(1, _ + 1)
,您可能希望编译器理解A
是Int
。但在确定_ + 1
的类型之前,它无法做到这一点。如果您使用def foo[A](a: A)(f: A => A)
代替它,它就可以工作。
在默认值中使用以前的参数。例如。 def foo(x: Int, y: Int = x)
无法编译,def foo(x: Int)(y: Int = x)
可以。{/ p>
函数参数本身可以用括号写成大括号:
def sum(a: Int, b: Int)(f: Int => Int): Int
sum(1, 2) { x => x*x }
最后一个块可以包含implicit parameters。