首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala2.8.1:更改延迟val的导入方式会影响评估时的效果。这是个虫子吗?

Scala2.8.1:更改延迟val的导入方式会影响评估时的效果。这是个虫子吗?
EN

Stack Overflow用户
提问于 2012-07-16 10:41:53
回答 2查看 316关注 0票数 0

这是按比例计算的。

我有个目标,康菲。在里面是一个懒惰的山谷,database

样本A:

代码语言:javascript
复制
import Config.database

 trait Dao {  
   protected val database = database  
}

样本B:

代码语言:javascript
复制
import Config

trait Dao {
  protected val database = Config.database
}

在config中,相关代码是:

代码语言:javascript
复制
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应该发出编译器警告,或者使堆栈溢出?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-07-16 10:55:54

我编译了这两个示例,然后用javap -c分析了字节码。(在我的示例中,Config.database是一个值为""的惰性字段;database的类型应该没有影响)。

第一个示例创建以下字节码:

代码语言:javascript
复制
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

}

第二个示例创建以下相同的字节码:

代码语言:javascript
复制
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的值带入顶级作用域,因此在编译过程中,解析器会认为它们是有效的,而没有前缀。

言简意赅,

代码语言:javascript
复制
import A.b
...
b

完全相同

代码语言:javascript
复制
...
A.b

导入只为您保存输入,它们不会更改代码的含义。如果您看到了不同之处,那么我相信,只有当您的一个导入隐藏了另一个定义时,这才有可能实现,因此,根据导入的措辞,对无前缀声明的解释是不同的。

票数 4
EN

Stack Overflow用户

发布于 2012-07-16 13:44:21

def可能导致堆栈溢出,但不会导致val溢出。val由getter和setter组成,因此分配是通过setter完成的,而读取是通过getter完成的,并且不存在循环。存储的值将与JVM使用:null初始化的值相同。

对于自引用变量没有任何警告,因为对此有有效的用例。例如,参见人们非常喜欢的普通“素数”或"fibonacci“流示例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11502658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档