大括号和圆括号在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
,所以您定义的是分部函数,分部函数需要大括号。因为您使用的是case
,您正在定义一个分部函数,分部函数需要大括号。社区正在努力标准化大括号和圆括号的使用,请参见Scala样式指南(第21页):
高阶方法调用的推荐语法是始终使用大括号,并跳过点:
val filtered = tupleList takeWhile { case (s1, s2) => s1 == s2 }
对于“正常”metod调用,应使用点和括号
val result = myInstance.foo(5, "Hello")
社区正在努力使大括号和圆括号的使用标准化,请参见Scala样式指南(第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.这里有两种不同的规则和推论:首先,当参数是函数时,Scala推断大括号,例如在list.map({u*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)
。这可能会引起混乱
功能/部分功能升
try {
block
} catch {
case pattern if guard => statements
case pattern => statements
} finally {
block
}
{
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 )
( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
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...
while (x < 10) { x += 1 }
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 {
_ + _
}