大括号和圆括号在Scala中的形式差异是什么,何时使用它们?
在括号大括号和圆括号在Scala中的形式差异是什么,何时使用它们?,scala,syntax,parentheses,braces,Scala,Syntax,Parentheses,Braces,在括号()和大括号{}中向函数传递参数的形式上有什么区别 我从这本书中得到的感觉是Scala非常灵活,我应该使用我最喜欢的一个,但我发现有些案例可以编译,而其他的则不能 例如(只是作为一个示例;我希望任何讨论一般情况的回复,而不仅仅是这个特定示例): =>错误:简单表达式的开始非法 val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 } =>很好。因为您使用的是case,所以您定义的是部分函数,部分函数需要大括号。社
()
和大括号{}
中向函数传递参数的形式上有什么区别
我从这本书中得到的感觉是Scala非常灵活,我应该使用我最喜欢的一个,但我发现有些案例可以编译,而其他的则不能
例如(只是作为一个示例;我希望任何讨论一般情况的回复,而不仅仅是这个特定示例):
=>错误:简单表达式的开始非法
val filtered = tupleList.takeWhile{ case (s1, s2) => s1 == s2 }
=>很好。因为您使用的是
case
,所以您定义的是部分函数,部分函数需要大括号。社区正在努力使大括号和圆括号的使用标准化,请参阅Scala Style Guide(第21页):
高阶方法调用的推荐语法是始终使用大括号,并跳过点:
val filtered = tupleList takeWhile { case (s1, s2) => s1 == s2 }
对于“正常”metod调用,应使用点和括号
val result = myInstance.foo(5, "Hello")
这里有两种不同的规则和推论:首先,当参数是函数时,Scala推断大括号,例如在
list.map(*2)
中,大括号是推断的,它只是list.map({u*2})
的一种较短形式。其次,Scala允许您跳过最后一个参数列表上的括号,如果该参数列表有一个参数并且它是一个函数,那么list.foldLeft(0)({u+}
可以写成list.foldLeft(0){{u+}
(或者list.foldLeft(0)({{u+})
,如果您想更加明确的话)
但是,如果您添加
case
,您会得到一个分部函数,而不是一个函数,Scala不会为分部函数推断大括号,因此list.map(case x=>x*2)
不起作用,但list.map({case x=>2*2})
和list.map{case x=>x*2}
will.我曾经试着写过这篇文章,但最终还是放弃了,因为规则有些分散。基本上,你必须掌握窍门
也许最好将注意力集中在大括号和圆括号可以互换使用的地方:将参数传递给方法调用时。当且仅当方法需要单个参数时,可以用大括号替换圆括号。例如:
List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter
List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter
while (x < 10) { x += 1 }
然而,为了更好地掌握这些规则,您还需要知道更多
使用parens增加编译检查
Spray的作者推荐round Paren,因为它们增加了编译检查。这对于像Spray这样的DSL尤其重要。通过使用parens,你告诉编译器应该只给它一行;因此,如果你不小心给它两个或更多,它会抱怨。现在大括号不是这种情况——例如,如果您忘记了某个操作符,那么您的代码将被编译,您将得到意外的结果,并且可能很难找到一个bug。下面是精心设计的(因为这些表达是纯粹的,至少会给出一个警告),但强调了这一点:
method {
1 +
2
3
}
method(
1 +
2
3
)
第一个编译,第二个给出预期的错误:')'但找到整数文本
。作者想写1+2+3
有人可能会说,对于带有默认参数的多参数方法,情况类似;在使用参数时,不可能意外地忘记用逗号分隔参数
冗长
一个重要的,经常被忽略的关于冗长的注释。使用大括号不可避免地会导致冗长的代码,因为清楚地说明结束大括号必须在其自己的行上:
…右大括号紧跟在最后一行之后
函数的行
许多自动重新格式化程序(如IntelliJ)将自动为您执行此重新格式化。所以,尽可能地坚持使用圆括号
中缀符号
使用中缀表示法时,如List(1,2,3)indexOf(2)
如果只有一个参数,可以省略括号,并将其写入List(1,2,3)indexOf 2
。这不是点表示法的情况
还请注意,如果有一个参数是多标记表达式,如x+2
或a=>a%2==0
,则必须使用括号来指示表达式的边界
多元组
因为有时可以省略括号,所以元组有时需要额外的括号,如((1,2))
,有时可以省略外括号,如(1,2)
。这可能会引起混乱
带有大小写的函数/部分函数文字
Scala具有函数和部分函数文本的语法。看起来是这样的:
{
case pattern if guard => statements
case pattern => statements
}
{
import stuff._
statement ; // ; optional at the end of the line
statement ; statement // not optional here
var x = 0 // declaration
while (x < 10) { x += 1 } // stuff
(x % 5) + 1 // expression
}
( expression )
您可以使用case
语句的唯一其他位置是match
和catch
关键字:
object match {
case pattern if guard => statements
case pattern => statements
}
不能在任何其他上下文中使用case
语句。因此,如果要使用大小写
,则需要大括号。如果您想知道函数和部分函数文字之间的区别,答案是:上下文。如果Scala需要一个函数,那么您将得到一个函数。如果它需要一个分部函数,则得到一个分部函数。如果两者都是预期的,则会给出一个关于歧义的错误
表达式和块
括号可用于生成子表达式。大括号可以用来生成代码块(这不是一个函数文字,所以请注意不要像使用函数文字一样使用它)。一个代码块由多个语句组成,每个语句可以是导入语句、声明或表达式。事情是这样的:
{
case pattern if guard => statements
case pattern => statements
}
{
import stuff._
statement ; // ; optional at the end of the line
statement ; statement // not optional here
var x = 0 // declaration
while (x < 10) { x += 1 } // stuff
(x % 5) + 1 // expression
}
( expression )
因此,因为表达式是语句,代码块是表达式,所以下面的所有内容都是有效的:
1 // literal
(1) // expression
{1} // block of code
({1}) // expression with a block of code
{(1)} // block of code with an expression
({(1)}) // you get the drift...
它们不能互换的地方
基本上,你不能用()
替换{}
,反之亦然。例如:
List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter
List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter
while (x < 10) { x += 1 }
所以,我希望这能有所帮助。我认为这是值得解释的
2 + { 3 } // res: Int = 5
val x = { 4 } // res: x: Int = 4
List({1},{2},{3}) // res: List[Int] = List(1,2,3)
def foo(f: Int => Unit) = { println("Entering foo"); f(4) }
foo( x => println(x) )
foo({ x => println(x) })
foo({ println("Hey"); x => println(x) })
foo { println("Hey"); x => println(x) }
foo { x => println(x) }
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
method {
1 +
2
3
}
method(
1 +
2
3
)
List(1, 2, 3).reduceLeft {
_ + _
}