Наследование и инициализация в Scala - PullRequest
2 голосов
/ 30 апреля 2011

У меня есть два класса Scala, которые выглядят так (перефразировано):

abstract class GenericParser[T] {
  val lineFilter : String => Boolean

  parseData()

  def parseData() : T {
    for( line <- .... if lineFilter(line) )
      // do things
  }
}

class SalesParser extends GenericParser[SalesRow] {
  val lineFilter = line => !line.startsWith("//")

  // ....
}

Проблема в том, что lineFilter равно null в parseData, возможно потому, что parseData вызывается, когда основной конструктор GenericParser все еще работает, поэтому подкласс не полностью инициализировал свои члены. *

Я могу обойти это, сделав lineFilter def вместо val, но это ожидаемое поведение? Не кажется правильным, что эта проблема должна стать очевидной только после получения NPE во время выполнения.

1 Ответ

6 голосов
/ 30 апреля 2011

Это действительно ожидаемое поведение, и это та же проблема, что и в этом вопросе:

Scala 2.8: как инициализировать дочерний класс

Вы можете в принципеСкопируйте и вставьте ответ на этот вопрос.Решения включают в себя:

  • def или lazy val вместо val
  • ранняя инициализация lineFilter
  • редизайн ваших классов вИзбегайте проблемы «вызова виртуального метода из конструктора суперкласса, который обращается к неинициализированным значениям подкласса».Например, почему вы хотите сохранить функцию фильтра в val или вернуть ее из def, в то время как она может быть реализована как метод?

    abstract class GenericParser[T] {
      def lineFilter(line: String): Boolean
    
      parseData()
    
      def parseData() : T {
        for( line <- .... if lineFilter(line) )
          // do things
      }
    }
    
    class SalesParser extends GenericParser[SalesRow] {
      def lineFilter(line: String) = !line.startsWith("//")
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...