0

これはscala.2.8.1にあります

オブジェクト構成があります。その中には、怠惰な val がありdatabaseます。

サンプル A:

import Config.database

 trait Dao {  
   protected val database = database  
}

サンプル B:

import Config

trait Dao {
  protected val database = Config.database
}

構成では、関連するコードは次のとおりです。

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 では、データベースが評価される順序が異なり
ます。正しい動作ではないと思います。確かに直感的ではありません。これがバグでない場合、誰かがこの動作が選択された理由を説明できますか?

特定の動作は、lazy val 内で、var が特定の値に設定されることです。サンプル A では、var がサンプル B よりも遅く設定されています。

編集だから、私は持っていることに気づきましたval database = database。したがって、インポートを変更すると、変数のシャドウイングが発生しましたが、自己参照 val がコンパイラの警告を発するか、スタックをオーバーフローするはずだと思いますか?

4

2 に答える 2

4

両方の例をコンパイルしてから、バイトコードを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

}

2 番目の例は、次の同一のバイトコードを作成します。

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

インポートは入力の手間を省くだけで、コードの意味を変更しません。違いが見られる場合、これはインポートの 1 つが別の定義を隠している場合にのみ可能であり、プレフィックスのない宣言はインポートの表現方法に応じて異なる方法で解釈されると思います。

于 2012-07-16T10:55:54.457 に答える
1

Adefはスタック オーバーフローを引き起こす可能性がありますが、val. Avalは getter と setter で構成されているため、代入は setter で行い、読み取りは getter で行い、サイクルは存在しません。格納された値は、JVM によって初期化された値と同じになりますnull

有効な使用例があるため、自己参照変数に関する警告はありません。たとえば、人々が好む一般的な「素数」または「フィボナッチ」ストリームの例を参照してください。

于 2012-07-16T13:44:21.720 に答える