Scala中apply方法括号调用与隐式参数冲突及语法疑问
解析Scala中
apply调用与隐式参数的冲突,以及("Bonjour".sorted)(3)的编译错误 先聊聊Cay Horstmann《Scala for the Impatient》里提到的一个常见坑:Scala的()调用语法有时候会和隐式参数机制冲突。比如你写"Bonjour".sorted(3)的时候,编译器会直接报错——因为sorted方法本身支持一个可选的Ordering隐式参数,但3根本不是合法的Ordering实例,编译器会误以为你是在给sorted传参,而不是要调用sorted返回字符串的apply方法(按索引取字符)。
针对这个问题,书里给出了两个靠谱的解决办法:
- 先把
sorted的结果存到变量里,再调用()(也就是apply):val result = "Bonjour".sorted result(3) - 直接显式调用
apply方法,消除歧义:"Bonjour".sorted.apply(3)
接下来是你最疑惑的点:为什么("Bonjour".sorted)(3)会编译失败?明明sorted返回的是String,Scala又会自动把String隐式转换成StringOps(它有apply方法支持按索引取值),用括号把表达式包起来难道不行吗?
问题的核心在于Scala的语法解析优先级:当你写下("Bonjour".sorted)(3)时,编译器会优先把它解析成「函数应用」——它会认为"Bonjour".sorted是一个返回函数的表达式,你现在要给这个函数传参数3。但实际上"Bonjour".sorted返回的是普通的String,不是函数类型,自然没法接收参数,所以编译报错。
对比一下可行的两种写法:
- 赋值给变量后,编译器处理
result(3)时,会先检查String有没有apply方法,发现没有后,就会触发隐式转换,把String转成StringOps,从而找到对应的apply方法; - 显式调用
.apply(3)则直接明确了你的意图,编译器不会有任何误解。
总结来说,就是语法解析的优先级让编译器误解了("Bonjour".sorted)(3)的含义,没有触发本该有的隐式转换,最终导致编译失败。
内容的提问来源于stack exchange,提问作者Guram Savinov
相关产品推荐
相关产品推荐

