web-dev-qa-db-ja.com

オブジェクトが別のソースファイルにある場合、オブジェクトがパッケージ<root>のメンバーではないのはなぜですか?

ルートパッケージで定義されたオブジェクトへのアクセスに問題があります。すべてのコードが1つのファイルに含まれている場合は正常に機能しますが、2つのファイルに分割すると、コンパイラーを通過できません。

これは正常に機能します。

packages.scalaと呼ばれるオールインワンファイル:

object Foo
  val name = "Brian"
}

package somepackage {
  object Test extends App {
    println(Foo.name)
  }
}

証人:

$ scalac packages.scala
$ scala -cp . somepackage.Test
Brian

しかし、コードを2つのファイルに分割すると、次のようになります。

packages.scala

object Foo {
  val name = "Brian"
}

packages2.scala

package somepackage {
  object Test extends App {
    println(Foo.name)
  }
}

それはすべて失敗します:

$ scalac packages.scala packages2.scala
packages2.scala:3: error: not found: value Foo

だから私はFoo絶対への参照を作ろうとします:

...
    println(_root_.Foo.name)
...

しかし、それも機能しません。

$ scalac packages.scala packages2.scala
packages2.scala:3: error: object Foo is not a member of package <root>

Fooがルートパッケージのメンバーでない場合、いったいどこでis it?

19
Martin McNulty

これが仕様の関連部分だと思います。

パッケージ外のトップレベルの定義は、特別な空のパッケージに挿入されると想定されています。そのパッケージには名前を付けることができないため、インポートできません。ただし、空のパッケージのメンバーは、資格なしで相互に表示されます。

ソース Scalaリファレンス§9.2パッケージ

ただし、packages2.scalaに次の情報がある場合、なぜ機能するのか私に聞かないでください。

object Dummy

package somepackage {
  object Test extends App {
    println(Foo.name)
  }
}
27
Debilski

Fooはルートパッケージのメンバーですが、参照することはできません。これはJVM言語では一般的なことです(Groovyの場合は デフォルトパッケージのJavaクラスにアクセスする方法 を参照してください Javaのデフォルトパッケージにクラスをインポートするための構文は何ですか?) )。 Scalaについても同じです。

Java回答から:

デフォルトのパッケージからクラスをインポートすることはできません。非常に小さなサンプルプログラムを除いて、デフォルトのパッケージの使用は避けてください。

Java言語仕様から:

名前のないパッケージから型をインポートすると、コンパイル時にエラーが発生します。

1つのファイルで機能する理由は、コンパイラーがすべてを一度に使用でき、コンパイラーがそれに対処するためです。これはスクリプトを許可するためだと思います。

話の教訓:スクリプトを作成していない場合は、デフォルトのパッケージを使用しないでください。

20
Matthew Farwell

メインのAppエントリポイントをテストにインポートしようとしたときに、これに遭遇しました。これは邪悪なハックかもしれませんが、package scalaエントリポイント定義の上部で、オブジェクトがグローバルに使用可能になっているようです。これは悪かもしれませんが、機能します。

例えば。 /src/main/scala/EntryPoint.scala

package scala

object EntryPoint extends App {
  val s = "Foo"
}

/src/test/scala/integration/EntryPointSuite.scala

package integration 
import org.scalatest.FlatSpec

class EntryPointSuite extends FlatSpec {
  "EntryPoint" should "have property s" in {
    val ep = EntryPoint.main()
    assert(ep.s == "Foo")
  }
}
0
Logister