Scala - Parentheses and Curly Brackets in Anonymous Functions

本文解析了Scala中匿名函数定义的灵活性及其可能导致的混淆,并详细解释了不同语法形式的区别及应用场景,尤其是在调用集合的map方法时的不同表现。
Scala gives a lot of flexibility in defining anonymous functions, and that might lead to a confussion. Jacek Laskowski asked an interesting question on  stackoverflow.com regarding of calling a map method on collection. To summarize it (given a list lst):

Why  lst map {c:Char => 1}  and  lst map ((c:Char) => 1)  work fine, but  lst map (c:Char => 1)  gives us compilation error:

 error: identifier expected but integer literal found.
       lst map (c:Char => 1)


To answer this question we should look into  Scala Language Specification , into part  6.23 Anonymous Functions .There is a description how anonymous function can be defined:

Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr
ResultExpr ::= (Bindings | ([‘implicit’] id | ‘_’) ‘:’ CompoundType) ‘=>’ Block
Bindings ::= ‘(’ Binding {‘,’ Binding} ‘)’
Binding ::= (id | ‘_’) [‘:’ Type]

As you can see Bindings requires to be placed inside two surrounding parentheses. So if anonymous function defines the type of the parameter, as in our example, it has to be defined in this way:

(c:Char)=>1

?

And the call to map should look like that: 

lst map((c:Char)=>1)

?
Also in the same part of reference documentation we can find:

If an anonymous function  (x: T) => e with a single typed parameter appears as the result expression of a block, it can be abbreviated to  x: T => e

So if anonymous function is defied as last expression in a code block, and has exacly one parameter, you can use abbreviated syntax, without parenthesis aroundc:Char, to define anonymous function. So, in our example, we can write c:Char => 1, but only when we place it inside a code block {c:Char => 1}. And we can call map function this way:

lst map({c:Char=>1})

?

or with abbreviated syntax without parenthesis:

lst map {c:Char=>1}

?
And that explains main question why  lst map {c:Char => 1}  is legal, and  lst map (c:Char => 1)  is not.

This is summarized in changelog at the end of the documentation (Changes in Version 2.1.7 (19-Jul-2006)):

Closure Syntax

The syntax of closures has been slightly restricted (§6.23). The form

x: T => E

is valid only when enclosed in braces, i.e. { x: T => E }. The following is illegal, because it might be read as the value x typed with the type T => E:

val f = x: T => E

Legal alternatives are:

val f = { x: T => E }
val f = (x: T) => E


Another way to specify anonymous functions:

If we look closer at specification we can see that it allows us to use another way to define anonymous function:

Expr ::= (Bindings | [‘implicit’] id | ‘_’) ‘=>’ Expr

We can see that we can define your anonymous function without parameter binding in those two ways (if we don't need to specify argument type):

lst map (c =>1)
// or
lst map (_=>1)

I hope that this article clarified how we can declare anonymous functions and it shouldn't cause a confusion any more.


-------------------------------------------------------

In general, there are many cases when you would prefer curly braces (e.g. multiline expressions, for comprehensions), but let's talk specifically about

when it's written on a single line, is there any inherent reason to use one over the other

In a second case it's not just curly braces, instead of parentheses, it's curly braces with ommited parentheses. Scala allows you to ommit parenthesis sometimes, and the later syntax is used to access to the niceties you got in partial functions (namely, pattern matching), so

lst foreach {x => println(s"you get the idea, $x")}

is actually

lst foreach({x => println(s"you get the idea, $x")})

which, as I said, can be useful from pattern matching POV:

val map = Map("foo" -> "bar")
map foreach { case (k, v) => println(s"key: $k, value: $v") }
// which is not possible with the usual parenthesis
<think>好的,我现在需要解决用户提出的关于Scala SDK 2.12.17中编译器类路径出现重复的scala-library.jar文件的问题。根据用户提供的引用内容,我需要先理解问题的原因,然后找到对应的解决方法。 首先,用户提到的错误信息是“No 'scala-library*.jar' in Scala compiler classpath”,但这里的问题其实是类路径中存在多个相同的jar文件导致冲突。这可能是因为项目配置中重复添加了Scala库,或者多个依赖项引入了不同版本的库。 参考引用[4]提到,当Idea找不到正确的Scala编译环境时,需要手动调整Project Structure中的Libraries设置,删除默认的库并替换成正确的SDK。这可能适用于解决库缺失的问题,但当前用户的情况是重复的库,所以可能需要类似的步骤来处理重复项。 另外,引用[5]展示了如何正确安装Scala SDK,包括解压和设置路径。如果用户的环境中有多个安装路径或者不同版本的SDK,可能导致类路径中存在多个jar文件。需要检查Scala SDK的安装位置是否正确,并确保项目只引用一个SDK。 可能的解决步骤包括: 1. 检查项目结构中的Libraries,移除重复的Scala库。 2. 确认构建工具(如SBT或Maven)的依赖配置,排除重复的依赖。 3. 确保Scala SDK的安装路径唯一,并在项目中正确配置。 此外,引用[3]提到通过一系列步骤可以解决类似问题,可能需要综合多个引用中的方法,如清理项目配置、重新导入依赖等。 需要验证这些步骤是否适用于重复jar文件的问题,可能需要用户检查具体的项目配置,例如在IDEA中查看Libraries和Modules的设置,或者检查构建文件中的依赖声明是否有冲突。如果存在多个版本的scala-library被引入,可能需要统一版本号或排除多余的依赖。</think>### 解决Scala编译器类路径中重复scala-library.jar文件问题 #### 问题原因分析 当Scala SDK的编译器类路径(classpath)中存在多个`scala-library*.jar`文件时,通常由以下原因导致: 1. **手动重复添加库文件**:在IDE(如IntelliJ IDEA)的`Project Structure > Libraries`中多次导入了相同或不同版本的Scala库[^4]。 2. **构建工具依赖冲突**:Maven/SBT配置中显式或隐式引用了多个不同版本的Scala库(如通过插件或传递依赖)[^1][^2]。 3. **SDK安装配置错误**:本地环境中安装了多个Scala SDK版本,且项目配置中混合引用了这些路径[^5]。 --- #### 分步解决方法 ##### 方法1:通过IDE清理重复库(推荐) 1. **打开项目配置**: 在IntelliJ IDEA中点击`File > Project Structure`。 2. **检查Libraries**: 在`Project Settings > Libraries`中,筛选所有名称包含`scala-library`的条目。 3. **删除重复项**: 保留与项目Scala版本(如2.12.17)一致的库,删除其他重复或冲突的条目。 4. **重新配置SDK**: 在`Project Settings > Global Libraries`中,确保仅关联一个正确的Scala SDK路径(例如`/usr/local/scala/scala-2.12.17`)[^5]。 ##### 方法2:通过构建工具排除冲突依赖 如果使用**SBT**或**Maven**,需检查依赖树: ```sbt // SBT示例:排查依赖 dependencyTree ``` 若发现其他依赖项间接引入了`scala-library`,显式排除重复项: ```sbt // 排除传递依赖中的scala-library libraryDependencies += "org.example" % "module" % "1.0" exclude("org.scala-lang", "scala-library") ``` ##### 方法3:重新安装并配置Scala SDK 1. **卸载旧版本**: 删除系统中可能存在的多个Scala安装目录(如`/usr/local/scala`下的多个版本)。 2. **安装单一版本**: 按照引用[5]的步骤,下载并解压`scala-2.12.17.tgz`到指定路径,确保环境变量`SCALA_HOME`指向该路径。 3. **更新IDE配置**: 在`File > Project Structure > Platform Settings > SDKs`中,移除旧的SDK,仅保留新安装的2.12.17版本。 --- #### 验证解决效果 1. 重新编译项目,观察是否仍报错。 2. 在终端执行以下命令检查类路径: ```bash # 查看实际加载的scala-library路径 echo $CLASSPATH | tr ':' '\n' | grep scala-library ``` 确保输出中仅包含一个`scala-library-2.12.17.jar`文件。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值