当你写
{ i: Int => 2 * i }
大括号是一个块,里面的东西是块的结果表达式。
语法是这里的 ResultExpr。请注意,参数名称后允许使用类型,如上。
这与没有的 Expr不同。
这是差异的示例:
scala> val is = List(1,2,3)
is: List[Int] = List(1, 2, 3)
块中的第一条语句有一个函数文字,如果我们指定类型,则需要括号的 Expr。最后一条语句是块的结果表达式,不需要括号:
scala> is map { val f = (i: Int) => 2*i; i: Int => 2*f(i) }
res0: List[Int] = List(4, 8, 12)
有时您不需要指定类型,因为它是从预期类型推断出来的,并且在 Expr 中没有类型,您可以省略括号:
scala> is map { val f: Int=>Int = i => 2*i; i: Int => 2*f(i) }
这些产品中的绑定(在规范中)是您在括号中的普通参数列表,可能具有类型。使用多个参数,您必须提供括号:
scala> is reduce { val f = (i:Int,j:Int) => i+j; (i:Int,j:Int) => 2*f(i,j) }
res2: Int = 18
有时你会看到一大块代码作为函数的参数。作为块的结果表达式,这是一个很大的函数文字,这就是为什么您会看到参数放在前面,没有括号或大括号:
scala> is map { i => val j = 2 * i; /* lots of LOC */ ; j }
res7: List[Int] = List(2, 4, 6)
这与下面的代码不同,它是多行代码块,最后是函数文字。该函数只返回j
或 2:
scala> is map { val j = 2; /* lots of LOC */ ; _ => j }
res8: List[Int] = List(2, 2, 2)
所以我们知道你不能写以下内容:
scala> is map (is: Int => 2)
<console>:1: error: identifier expected but integer literal found.
is map (is: Int => 2)
^
在这种情况下,什么样的标识符是有意义的?怎么样:
scala> is map (is: Int => Int)
这产生了令人愉快的结果(剧透警报):
java.lang.IndexOutOfBoundsException: 3
这有效:
scala> val js = List(0,1,2)
js: List[Int] = List(0, 1, 2)
scala> js map (js: Int => Int)
res0: List[Int] = List(0, 1, 2)
js
in parens 只是一个值,显然不是参数,类型是类型归属。该值可以是一个后缀表达式,所以这有效(或者更确切地说,编译时带有关于后缀运算符语法的功能警告):
scala> js map (js init: Int => Int)
warning: there were 1 feature warning(s); re-run with -feature for details
java.lang.IndexOutOfBoundsException: 2
此答案的更多解释:
https://stackoverflow.com/a/13873899/1296806
由于认为括号和花括号可以以某种方式交换,会引起一类混淆。但是我发现将大括号视为是很清楚的BlockExprs
,这就是它们的含义。然后更容易记住,例如,当您在函数应用程序中使用大括号时,并没有什么神奇之处:您只是提供了一个block。
块是一堆副作用语句,后面跟着一个结果语句。这对函数式程序员来说是显而易见的,也许。但它澄清了大括号中的最后一件事是ResultExpr
.
(脚注:类主体的大括号当然是不同的。)