scala2.10中采纳了SIP-18:模块化语言特性

引入的原因是scala中的某些特性比较难懂或有些晦涩,或有些特性是试验性质。
这些特性在普通场景下不鼓励使用,但在特定场景下又可能需要。所以引入了“显式引入语言特性”的做法。

举例来说,在2.10的repl下定义隐式转换:

scala> implicit def string2MyString(s:String) = new MyString(s)

warning: there were 1 feature warning(s); re-run with -feature for details
string2MyString: (s: String)MyString

好,我们重新启动repl,启用 -feature 选项:

$ scala -feature

scala> class MyString(str:String) { def say() {println(str)} }
defined class MyString

scala> implicit def string2MyString(s:String):MyString = new MyString(s)
<console>:8: warning: implicit conversion method string2MyString should be enabled
by making the implicit value language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
See the Scala docs for value scala.language.implicitConversions for a discussion
why the feature should be explicitly enabled.
   implicit def string2MyString(s:String):MyString = new MyString(s)
                ^
string2MyString: (s: String)MyString

这回给出了详细的警告信息,使用隐式转换方法,建议在代码中引入language单例的implicitConversions成员: import scala.language.implicitConversions 或者 编译时指定-language:implicitConversions参数

为什么要控制隐式转换这一特性(要显式启用)?是因为过度使用隐式转换会有很多陷阱,而现在已经有这个趋势,因为隐式转换的强大而被过度使用。另外,相对隐式转换,采用隐式参数对设计更好一些。

类似的控制还有后缀操作符:

scala> "hello" length //中间用空格,省略了点

也会给出警告提示import scala.language.postfixOps或编译时指定参数-language:postfixOps
这是因为后缀操作符与分号推理(semicolon inference)容易冲突,举个例子:

//有参方法:a.foo(b) 也可以写成 a foo b
//无参方法:a.foo() 也可以写成 a foo
//如果一个类中同时定义了上面两个方法
scala> class A { def foo(i:Int)=i+1; def foo()=2}

// 没有分号,解析为 a.foo(2)
scala> val r = { a foo 2 }
r: Int = 3

// 有分号的话解析为 a.foo() 分号后边的是下一条语句
scala> val r = { a foo; 2 }
warning: there were 1 feature warning(s); re-run with -feature for details
r: Int = 2

// 但在换行情况下
scala> :pas
// Entering paste mode (ctrl-D to finish)
val r = {
    a foo // 这里没写分号
    2
}
// Exiting paste mode, now interpreting.

r: Int = 3
结果被解析为 a.foo(3) !!

如果没有分号,就无法解析为a.foo(),总会把下一条语句也当作参数,比如:

scala> :pas
// Entering paste mode (ctrl-D to finish)
var r = {
    a foo // 这里没有写分号
    println("another")
}
// Exiting paste mode, now interpreting.

<console>:19: error: type mismatch;
found   : Unit
required: Int
    println("another")
           ^

所以为了避免这种情况,后缀操作符也不鼓励,只有特定场景需要时(DSL),显式的打开这个选项;否则会警告。

另外不鼓励的特性还有:存在类型(existentials)、高阶类(higherKinds)、动态类(dynamics)、反射调用(reflectiveCalls)

scala2.10中采纳了SIP-18:模块化语言特性》上有1条评论

  1. Pingback引用通告: scala雾中风景(18): postfix operator的问题 | 在路上

发表评论

电子邮件地址不会被公开。 必填项已用*标注