凯·霍斯特曼(Cay Horstmann)的书《不耐烦的scala》中有一个关于应用方法的注释:
有时,()表示法与另一个Scala功能冲突:
隐式参数。例如,表达式"Bonjour".sorted(3)
产生错误,因为可以有选择地调用已排序的方法
排序,但3不是有效的排序。
解决方案是将"Bonjour".sorted
分配给变量并对其应用调用,例如:
val result = "Bonjour".sorted
result(3)
或致电明确申请:
"Bonjour".sorted.apply(3)
但是为什么这不起作用并产生编译错误:
("Bonjour".sorted)(3)
排序的方法返回一个
String
,可以将其隐式转换为StringOps
,并且括号用于包装字符串表达式。为什么编译器不接受调用
StringOps
的apply方法? 最佳答案
您可以使用-Xprint:parser
来查看这些paren是否被提前丢弃:
scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x
scala> "hi".scaled(5)
res0: String = hihihihihi
scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi
scala> "hi".scaled(5)(3)
res2: Char = i
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi
scala> :se -Xprint:parser
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of parser]] // <console>
package $line8 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.x;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res4 = {
implicit val n: Int = 5;
"hi".scaled(3)
}
}
}
}
}
res4: String = hihihi
scala>
多余的父母什么也没做。编译器只看到一个应用程序
expr(args)
。因为它是一个应用程序,所以您不会获得“隐式应用程序”转换。无论如何,方法
scaled
的含义取决于所需的类型。我们期望额外的paren有所作为的原因是parens会覆盖运算符的优先级。但是
(x)
只是x
。规范实际上对此很明确:
e(args)
要求e
适用于args
。特别是,根据e
的参数类型对args进行类型检查。如果
e(args)
是值,则将e.apply(args)
用作e
,但是scaled
是方法。您希望“隐式应用程序”插入隐式参数,但这仅在尚未应用
e
时适用。或者,可以将(e)(args)
视为(e(_))(args)
,即(x => e(x))(arg)
。当以
e.apply(arg)
编写时,e
不是像e(arg)
这样的应用程序,因此您将从诸如隐式应用程序之类的转换中受益。