我正在使用scala 2.10.3
,我注意到以下行为
object TestConstantScala {
final val str1 : String = "foo:" + number1
final val number1 : Int = 123
final val number2 : Int = 123
final val str2 : String = "foo:" + number2
def main(args: Array[String]){
System.out.println(str1)
System.out.println(str2)
}
}
输出:
foo:0
foo:123
我的问题是为什么订单有所作为。另外,如果我省略Int
定义,它返回的行为正常
答案 0 :(得分:6)
没有类型归属(: Int
)number1
甚至不作为字段存在,因此不需要初始化。相反,编译器创建一个直接返回值123
的访问器方法,并在构造函数中使用文字值123
来初始化str1
。
为什么在存在类型归属时会创建字段?在这种情况下它确实没有意义,但有时类型归属可能需要执行值转换的代码,例如装箱基元或应用隐式转换。由于语义原因(对象标识,隐式转换中的副作用)和效率,这些操作应该只进行一次。因此,结果必须存储在字段中。
因此,没有类型归属的行为是初始化为常量值的final
原始字段的优化,并且当存在类型归属时,编译器不够智能地应用优化。
这是一个更小的例子:
object TestConstantScala {
final val brokenStr: String = "foo:" + brokenNumber
final val brokenNumber: Int = 123
final val workingStr: String = "foo:" + workingNumber
final val workingNumber = 123
println(brokenStr)
println(workingStr)
}
这是scalac -Xprint:constructors
的输出,在将初始化移动到构造函数后立即显示AST:
[[syntax trees at end of constructors]] // test18.scala
package <empty> {
object TestConstantScala extends Object {
final private[this] val brokenStr: String = _;
final <stable> <accessor> def brokenStr(): String = TestConstantScala.this.brokenStr;
final private[this] val brokenNumber: Int = _;
final <stable> <accessor> def brokenNumber(): Int = TestConstantScala.this.brokenNumber;
final private[this] val workingStr: String = _;
final <stable> <accessor> def workingStr(): String = TestConstantScala.this.workingStr;
final <stable> <accessor> def workingNumber(): Int(123) = 123;
def <init>(): TestConstantScala.type = {
TestConstantScala.super.<init>();
TestConstantScala.this.brokenStr = "foo:".+(scala.Int.box(TestConstantScala.this.brokenNumber()));
TestConstantScala.this.brokenNumber = 123;
TestConstantScala.this.workingStr = "foo:".+(scala.Int.box(123));
scala.this.Predef.println(TestConstantScala.this.brokenStr());
scala.this.Predef.println(TestConstantScala.this.workingStr());
()
}
}
}
请注意workingNumber
没有字段,只有访问者,以及构造函数workingStr
中的"foo:".+(scala.Int.box(123))
是如何初始化的。
答案 1 :(得分:0)
有两个问题在起作用:
final
关键字)来获得有效模式匹配的方法。来自Scala语言规范,第4.1节“值声明和定义”
常量值定义的格式为
final val x = e
其中e是常数表达式(§6.24)。必须存在最终修饰符 不能给出类型注释。对常数值x的引用本身就是 被视为常数表达;在生成的代码中,它们被替换为定义 右侧e 。