这个谜题也是邮件列表里看到的,当使用下面的代码时,编译正常:
object ListTests1 extends App {
val numbers: List[Int] = (1 to 10).toList
println(s"numbers: $numbers")
}
但当把toList
方法前边的点给去掉时,编译居然报错:
scala> :pas
// Entering paste mode (ctrl-D to finish)
object ListTests1 extends App {
val numbers: List[Int] = (1 to 10) toList
println(s"numbers: $numbers")
}
// Exiting paste mode, now interpreting.
<console>:9: error: type mismatch;
found : Unit
required: Int
println(s"numbers: $numbers")
^
可能第一眼以为是(1 to 10) toList
这种写法有问题,但直接在repl下运行这一句的话,是ok的,只是警告toList是一个后缀操作符
scala> val numbers: List[Int] = (1 to 10) toList
<console>:7: warning: postfix operator toList should be enabled
by making the implicit value scala.language.postfixOps visible.
This can be achieved by adding the import clause 'import scala.language.postfixOps'
or by setting the compiler option -language:postfixOps.
See the Scala docs for value scala.language.postfixOps for a discussion
why the feature should be explicitly enabled.
val numbers: List[Int] = (1 to 10) toList
^
numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
这里有趣的是,这行表达式跟下一行表达式的结果也可以组成一个表达式;在使用后缀操作符的情况下,方法后边的表达式,优先解析为参数对待。这里本来 toList
方法是一个无参方法,但它的结果类型List
是可以apply
的,所以toList
方法后边也可以接受Int
类型的参数;而下一行的println
得到是一个Unit
类型,所以错误。
类似这个例子:
object Test {
def say = println("say nothing")
def say(s:String) = println("say " + s)
}
定义了2个say方法,一个无参和一个String类型参数的,当调用
Test.say
println("hello")
上面语句被解释为2个表达式,第一句调用的是无参的 say 方法,而写为:
Test say
println("hello")
这种情况下被解析为Test.say(println("hello"))
把下一行表达式的结果当作say的参数,因为类型不匹配而失败。如果在第一行加一个分号行为就不一样了:
Test say;
println("hello")
postfix operator对于设计DSL很有用,但平常程序里最好还是不要用。
相关内容:scala2.10中采纳了SIP-18:模块化语言特性