Scala правильный способ инициализировать изменения в полях времени выполнения: заполнитель / ноль, элемент Нет или ноль? - PullRequest
1 голос
/ 13 марта 2020

Я получил класс с полями, значение которого при инициализации неизвестно. Но после этого во время выполнения эти значения будут получены и установлены в поля только единицы .

Я хочу решить, какую первую инициализацию лучше использовать для этих полей. Как я читал, есть такие методы:

  1. с использованием заполнителя _ или null [ Плохой способ ]:

    var name: String = _
    var nextUser: User = null
    
  2. с использованием None, а затем в моем коде Some(v) [ Хорошо, но многословно ]:

    var name: Option[String] = None
    var nextUser: Option[User] = None
    
  3. с использованием "ноль" элемент:

    var name: String = ""
    var nextUser: User = new User()
    
  4. с использованием заглушки:

    var name: String = "undefined"
    var nextUser: User = UndefinedUser
    

Я вижу 3 проблемы:

  1. Подробно получать значения из Some() записи в любое время .get или использования match/case
  2. неправильно использовать var для поля, которое действительно будет установлено значением только один раз, но во время выполнения
  3. плохо писать updateUser -подобные методы

Теперь я использую None в этих полях, потому что для некоторых типов, которые нет в моей библиотеке, нет никакого constructor или empty \ "нулевого" значения:

class ClassWithLazyFields {

  var name: String = ""
  var age: Int = 0

  //here, after first asignment as `None` i will set it values only one time
  var myThread: Option[Thread] = None
  var nextUser: Option[User] = None
  var myTransformUnit: Option[TransformUnit] = None

  def updateUser(u: User): Unit = {
    nextUser = u
  }
}

//after first asignment as `None` i set nextUser value like that
classInstance.updateUser(userCat)

// bad ".get" in callings
val name = classInstance.myThread.get.name
val hoursToStart = classInstance.myTransformUnit.get.waitTime.hours

// or more verbose match/case
val hoursToStart = classInstance.myTransformUnit match {
  case Some(v) => v.waitTime.hours
  case None => 0
}

Что вы можете посоветовать мне? Мне нужно что-то вроде lazy var или любой хороший совет.

1 Ответ

3 голосов
/ 13 марта 2020

Совет заключается в том, чтобы в первую очередь избегать использования таких изменяемых структур данных.

Сделайте класс неизменным и измените методы, например updateUser, чтобы возвращать новый обновленный экземпляр вместо изменения текущего экземпляра.

Но если вы должны это сделать, Option специально предназначен для случаи, когда значения могут присутствовать или не присутствовать. Такие методы, как map и getOrElse, позволяют легко (и безопасно) использовать значения Option с очень небольшими накладными расходами.


Например, так вы можете безопасно вычислять name и hoursToStart:

val name = classInstance.myThread.fold("NoName")(_.name)
val hoursToStart = classInstance.myTransformUnit.fold(0)(_.waitTime.hours)

Если вы хотите использовать несколько значений Option, используйте for следующим образом:

for {
  thread <- classInstance.myThread
  user <- classInstance.nextUser
  unit <- classInstance.myTransformUnit
} {
  // Code that uses thread, user, and unit
}

Код будет вызываться только в том случае, если все три значения не None.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...