2015-09-01 14 views
0

Дано:Инициализация объекта зависит от другого объекта

SRC/главная/Scala/сеть/Foo.scala

package net 

object Foo { 
    ??? 
    val x = 100 
} 

SRC/главная/Scala/сеть/Bar.scala

package net 

object Bar { 
import Foo._ 
def speak = "bar!" 
} 

Я открыл REPL позвонить Bar#speak:

scala> import net.Bar 
import net.Bar 

scala> Bar.speak 
res0: String = bar! 

Я ожидал, что Bar инициализируется Foo, в результате чего исключение получают с помощью ???.

Почему это исключение не было выбрано?

+0

Импорт никогда не имеет эффектов. –

ответ

2

Это то, что вы имели:

scala> object Foo { 
    | ??? 
    | val x = 100 
    | } 
defined object Foo 

scala> object Bar { 
    | import Foo._ 
    | def speak = "bar!" 
    | } 
defined object Bar 

scala> Bar.speak 
res0: String = bar! 

scala> Bar.speak 
res1: String = bar! 

import Foo._ означает, что для целей компиляции для разрешения имен членов Foo будут доступны в объеме. Это не значит, что Foo должен быть инициализирован в этот момент - здесь Scala ленив. Теперь сравните с этим примером:

scala> object Foo { 
    | ??? 
    | val x = 100 
    | } 
defined object Foo 

scala> object Bar { 
    | val blowUp = Foo.x 
    | def speak = "bar!" 
    | } 
defined object Bar 

scala> Bar.speak 
scala.NotImplementedError: an implementation is missing 
    at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225) 
    ... 37 elided 

Это заставляет Foo получить инициализирован, поскольку он использует Foo.x в своей собственной инициализации, который в свою очередь запускается вызова speak. Упрощенный пример:

scala> object Foo { 
    | ??? 
    | val x = 100 
    | } 
defined object Foo 

Не взорвал. Foo не инициализирован.

scala> Foo.x 
scala.NotImplementedError: an implementation is missing 
    at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225) 
    ... 35 elided 

Теперь мы вынудили Foo получить инициализацию.

Короче говоря, здесь есть две важные вещи: 1) ленивая инициализация по ссылке/вызову и 2) импорт не вызывает инициализации.

2

Потому что Bar на самом деле не ссылается на Foo. Если Bar.speak использовал Foo или Foo.x в некотором роде, вы получили бы ожидаемое исключение. import помещает членов Foo в область действия, но не получает к ним доступа.

Смежные вопросы