我对此Scala符号感到有点困惑:
List(1, 2, 3).foldLeft(0)((x, acc) => acc+x)
两者" 0"而函数是foldLeft的参数,为什么它们在两个相邻的括号组中传递?我将此视为工作:
List(1, 2, 3).foldLeft(0, ((x, acc) => acc+x))
但它没有。任何人都可以向我解释这个吗?另外,如何以及为什么声明这种类型的功能?感谢
答案 0 :(得分:6)
Scala允许您拥有多个参数列表:
def foo(a: Int)(b: String) = ???
def bar(a: Int)(b: String)(c: Long) = ???
将此语法用于foldLeft的原因是编译器进行类型推断的方式:前一组参数中的已推断类型用于推断连续参数组中的类型。如果是foldLeft,它允许你删除(x, acc)
旁边的类型归属,所以代替:
List(1, 2, 3).foldLeft(0)((x: Int, acc: Int) => acc+x)
你可以写
List(1, 2, 3).foldLeft(0)((x, acc) => acc+x)
答案 1 :(得分:2)
这是multiple parameter lists in Scala的一个例子。它们实际上只是普通方法调用的语法糖(如果你用javap
查看类文件的方法签名,你会看到在编译成Java字节码时它们都被合并为一个参数列表)。支持多个参数列表的原因有两个:
{}
中的函数文字替换带有单个参数的参数列表。例如,您的代码可以重写为List(1, 2, 3).foldLeft(0) { (x, acc) => acc+x }
,这可能被认为更具可读性。 (然后,在这种情况下,我只使用List(1, 2, 3).foldLeft(0)(_+_)
...)能够使用这样的花括号使用户可以声明看起来更像本机语法的新函数。一个很好的例子是the react
function for Actors。z
的初始foldLeft
值用于推断函数参数的结果类型(和左参数类型)。答案 2 :(得分:1)
因为在Scala中,您可以在由()
def test(a: String)(b: String)(implicit ev: Something) { }
最实际的情况是需要上下文绑定或currying,例如范围内可用的特定implicit
定义。
例如,Future
会期望implicit executor
。看here。
如果你看一下foldLeft
方法的定义,你会看到第一个参数是一个累加器,第二个参数是一个用于currying的函数。
def foldLeft[B](z: B)(op: (B, A) ⇒ B): B
圆括号是一个非常有用的关注点分离。 此外,一旦您使用以下方法定义方法:
def test(a: String)(b: String)
You can't call it with: test("a", "b");