这是按比例计算的。
我有个目标,康菲。在里面是一个懒惰的山谷,database。
样本A:
import Config.database
trait Dao {
protected val database = database
}样本B:
import Config
trait Dao {
protected val database = Config.database
}在config中,相关代码是:
lazy val database =
somethingFromAFile match {
case "a" => databaseA
case "b" => databaseB
case "c" => databaseC
}
lazy val databaseA = makeDB("a")
lazy val databaseB = makeDB("b")
lazy val databaseC = makeDB("c")
var changes = throw new Exception ("Not yet initialised")
private def makeDB(db: String) = {
db match {
case "a" => var changes = x => 2*x; ... //database making stuff
case "a" => var changes = x => 3*x; ...
case "a" => var changes = x => 4*x; ...
}
}在样本A和样本B中,数据库的评估顺序是不同的。
我认为这不应该是正确的行为。当然这不是直觉。如果这不是一个错误,有人能解释为什么选择这种行为吗?
具体的行为是在懒惰的val中,将var设置为某个值。在样本A中,var的设置比在样本B中晚。
编辑,所以我刚刚意识到我得到了val database = database。因此,更改导入会导致变量的隐藏,尽管我预计自引用val应该发出编译器警告,或者使堆栈溢出?
发布于 2012-07-16 10:55:54
我编译了这两个示例,然后用javap -c分析了字节码。(在我的示例中,Config.database是一个值为""的惰性字段;database的类型应该没有影响)。
第一个示例创建以下字节码:
Compiled from "foo.scala"
public class foo extends java.lang.Object implements scala.ScalaObject{
public java.lang.String db();
Code:
0: aload_0
1: getfield #11; //Field db:Ljava/lang/String;
4: areturn
public foo();
Code:
0: aload_0
1: invokespecial #17; //Method java/lang/Object."<init>":()V
4: aload_0
5: getstatic #23; //Field Config$.MODULE$:LConfig$;
8: invokevirtual #26; //Method Config$.database:()Ljava/lang/String;
11: putfield #11; //Field db:Ljava/lang/String;
14: return
}第二个示例创建以下相同的字节码:
Compiled from "foo.scala"
public class foo extends java.lang.Object implements scala.ScalaObject{
public java.lang.String db();
Code:
0: aload_0
1: getfield #11; //Field db:Ljava/lang/String;
4: areturn
public foo();
Code:
0: aload_0
1: invokespecial #17; //Method java/lang/Object."<init>":()V
4: aload_0
5: getstatic #23; //Field Config$.MODULE$:LConfig$;
8: invokevirtual #26; //Method Config$.database:()Ljava/lang/String;
11: putfield #11; //Field db:Ljava/lang/String;
14: return
}我甚至看不出两者表面上的区别。
这与导入实际上是一致的--它们只是一种方法,可以防止您在任何地方都必须完全限定引用。import Config._什么也不做;它只是将来自Config的值带入顶级作用域,因此在编译过程中,解析器会认为它们是有效的,而没有前缀。
言简意赅,
import A.b
...
b完全相同
...
A.b导入只为您保存输入,它们不会更改代码的含义。如果您看到了不同之处,那么我相信,只有当您的一个导入隐藏了另一个定义时,这才有可能实现,因此,根据导入的措辞,对无前缀声明的解释是不同的。
发布于 2012-07-16 13:44:21
def可能导致堆栈溢出,但不会导致val溢出。val由getter和setter组成,因此分配是通过setter完成的,而读取是通过getter完成的,并且不存在循环。存储的值将与JVM使用:null初始化的值相同。
对于自引用变量没有任何警告,因为对此有有效的用例。例如,参见人们非常喜欢的普通“素数”或"fibonacci“流示例。
https://stackoverflow.com/questions/11502658
复制相似问题