在括号()和大括号{}中传递参数给函数之间的形式区别是什么?

我从《Scala编程》这本书中得到的感觉是,Scala非常灵活,我应该使用我最喜欢的那一种,但我发现有些情况可以编译,而其他情况则不行。

例如(只是作为一个例子;我很感激任何讨论一般情况的回复,而不仅仅是这个特定的例子):

val tupleList = List[(String, String)]()
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 )

=>错误:简单表达式的非法开始

val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

= >好。


当前回答

我不认为Scala中的花括号有什么特别或复杂的地方。要掌握它们在Scala中看似复杂的用法,只需记住几件简单的事情:

花括号形成一个代码块,计算到最后一行代码(几乎所有语言都这样做) 如果需要,可以使用代码块生成函数(遵循规则1) 除了case子句外,单行代码可以省略花括号(Scala选择) 括号可以在函数调用中省略,将代码块作为参数(Scala选择)

让我们根据以上三条规则来解释几个例子:

val tupleList = List[(String, String)]()
// doesn't compile, violates case clause requirement
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 ) 
// block of code as a partial function and parentheses omission,
// i.e. tupleList.takeWhile({ case (s1, s2) => s1 == s2 })
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

// curly braces omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft(_+_)
// parentheses omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft{_+_}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).reduceLeft _+_ // res1: String => String = <function1>

// curly braces omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0)(_ + _)
// parentheses omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0){_ + _}
// block of code and parentheses omission
List(1, 2, 3).foldLeft {0} {_ + _}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).foldLeft(0) _ + _
// error: ';' expected but integer literal found.
List(1, 2, 3).foldLeft 0 (_ + _)

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }
// block of code that just evaluates to a value of a function, and parentheses omission
// i.e. foo({ println("Hey"); x => println(x) })
foo { println("Hey"); x => println(x) }

// parentheses omission, i.e. f({x})
def f(x: Int): Int = f {x}
// error: missing arguments for method f
def f(x: Int): Int = f x

其他回答

因为使用的是case,所以定义的是偏函数,而偏函数需要花括号。

理想编码风格中的圆括号基本上用于单行代码。 但如果特定的代码段是多行,那么使用大括号是更好的方法。

社区正在努力标准化大括号和圆括号的使用,参见Scala风格指南(第21页):http://www.codecommit.com/scala-style-guide.pdf

对于高阶方法调用,推荐的语法是总是使用大括号,并跳过点:

val filtered = tupleList takeWhile { case (s1, s2) => s1 == s2 }

对于“普通”方法调用,应该使用点和圆括号。

val result = myInstance.foo(5, "Hello")

我不认为Scala中的花括号有什么特别或复杂的地方。要掌握它们在Scala中看似复杂的用法,只需记住几件简单的事情:

花括号形成一个代码块,计算到最后一行代码(几乎所有语言都这样做) 如果需要,可以使用代码块生成函数(遵循规则1) 除了case子句外,单行代码可以省略花括号(Scala选择) 括号可以在函数调用中省略,将代码块作为参数(Scala选择)

让我们根据以上三条规则来解释几个例子:

val tupleList = List[(String, String)]()
// doesn't compile, violates case clause requirement
val filtered = tupleList.takeWhile( case (s1, s2) => s1 == s2 ) 
// block of code as a partial function and parentheses omission,
// i.e. tupleList.takeWhile({ case (s1, s2) => s1 == s2 })
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }

// curly braces omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft(_+_)
// parentheses omission, i.e. List(1, 2, 3).reduceLeft({_+_})
List(1, 2, 3).reduceLeft{_+_}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).reduceLeft _+_ // res1: String => String = <function1>

// curly braces omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0)(_ + _)
// parentheses omission, i.e. List(1, 2, 3).foldLeft(0)({_ + _})
List(1, 2, 3).foldLeft(0){_ + _}
// block of code and parentheses omission
List(1, 2, 3).foldLeft {0} {_ + _}
// not both though it compiles, because meaning totally changes due to precedence
List(1, 2, 3).foldLeft(0) _ + _
// error: ';' expected but integer literal found.
List(1, 2, 3).foldLeft 0 (_ + _)

def foo(f: Int => Unit) = { println("Entering foo"); f(4) }
// block of code that just evaluates to a value of a function, and parentheses omission
// i.e. foo({ println("Hey"); x => println(x) })
foo { println("Hey"); x => println(x) }

// parentheses omission, i.e. f({x})
def f(x: Int): Int = f {x}
// error: missing arguments for method f
def f(x: Int): Int = f x

There are a couple of different rules and inferences going on here: first of all, Scala infers the braces when a parameter is a function, e.g. in list.map(_ * 2) the braces are inferred, it's just a shorter form of list.map({_ * 2}). Secondly, Scala allows you to skip the parentheses on the last parameter list, if that parameter list has one parameter and it is a function, so list.foldLeft(0)(_ + _) can be written as list.foldLeft(0) { _ + _ } (or list.foldLeft(0)({_ + _}) if you want to be extra explicit).

但是,如果添加case,就会得到一个部分函数,而不是其他函数,Scala不会推断部分函数的花括号,所以list。Map (case x => x * 2)将不起作用,但两者都列出。映射({case x => 2 * 2})和列表。映射{case x => x * 2}将。