2016-05-27 6 views
5

Я учусь Scala и в Programming in Scala 3rd Ed, Ch 10, Page 225, раздел Overriding methods and fields, он говоритScala перекрывая четкости с Валом бросает NPE

Единый принцип доступа только один аспект, где Scala рассматривает поля и методы более равномерно, чем Java , Другое отличие - , что в Scala поля и методы принадлежат одному и тому же пространству имен. Этот позволяет полю переопределять метод без параметров. Для Например, вы можете изменить реализацию содержания в классе ArrayElement из метода в поле без необходимости модифицировать абстрактное определение метода содержания в классе элемента, как показано в листинге 10.4:

Мои код, основанный на примере

с четкости

abstract class Element { 
    def contents: Array[String] 

    val height = contents.length 

    val width = if (height == 0) 0 else contents(0).length 
} 


class ArrayElement(contnts: Array[String]) extends Element { 
    def contents: Array[String] = contnts 
} 

// -- 
val ae = new ArrayElement(Array("hello", "world")) 
ae.height 
ae.width 

я получаю

ae: ArrayElement = [email protected] 
res0: Int = 2 
res1: Int = 5 

с Def переопределен, как Валу в ArrayElement

abstract class Element { 
    def contents: Array[String] 

    val height = contents.length 

    val width = if (height == 0) 0 else contents(0).length 
} 


class ArrayElement(contnts: Array[String]) extends Element { 
    val contents: Array[String] = contnts 
} 

// -- 
val ae = new ArrayElement(Array("hello", "world")) 
ae.height 
ae.width 

я NPE в

java.lang.NullPointerException 
    at #worksheet#.Element.<init>(scratch.scala:4) 
    at #worksheet#.ArrayElement.<init>(scratch.scala:10) 
    at #worksheet#.ae$lzycompute(scratch.scala:15) 
    at #worksheet#.ae(scratch.scala:15) 
    at #worksheet#.#worksheet#(scratch.scala:14) 

Что мне не хватает?

ответ

7

Поля уровня класса инициализируются перед чем-либо еще, что означает, что назначается null. Вы можете сделать объявление lazy val, и оно не будет инициализировано до его вызова. Именно по этой причине def работает. Лучший способ, хотя, вместо того, чтобы создать открытое поле класса затенения частного поля конструктора, чтобы просто сделать конструктор поле общественности, как это:

class ArrayElement(val contnts: Array[String]) extends Element {} 

Поскольку есть родительский класс в игре здесь тоже было бы хорошо отметить его как переопределение;

class ArrayElement(override val contnts: Array[String]) extends Element {} 

Если это будет без гражданства класса контейнера данных, хотя, лучший вариант, чтобы сделать его case class, который (среди нескольких других вещей) имеет государственно-по-умолчанию полей.

case class ArrayElement(override val contnts: Array[String]) extends Element 

Это гораздо более идиоматический Скал и это обеспечит вам значение на основе equals, hashCode, сопоставление с образцом, более простой конструкцией (нет необходимости new)

+1

Истинных. Простое эмпирическое правило - никогда не ссылаться на абстрактную 'def' внутри' val', так как нет никаких гарантий, что 'def' будет иметь какое-либо значение к тому времени, когда будут инициализированы' val '. @Daenyth, я отредактировал ваш комментарий, чтобы предоставить другой вариант – Sergey

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