Подтвердить что ты не робот

Scala: как инициализировать объект, используя значения по умолчанию

Я думаю, что это будет лучше объяснено с помощью примера

У меня есть класс case

case class Person(name: String = "no name", surname: String = "no surname")

И я хочу создать общую функцию для ее заполнения, например, json-сообщение, которое может не указывать все поля

Я знаю, что для использования значений по умолчанию простой ответ заключается не в том, чтобы передать их конструктору, но если у меня есть несколько полей, которые могут появляться или не появляться в json, мне придется использовать огромное предложение switch, охватывающее все возможная комбинация отсутствующих параметров. В этом случае, прочитав json, я должен позаботиться о имени и фамилии, имени, фамилии, имени и фамилии... (Надеюсь, я ясно дал понять).

Чтобы быть более точным, я пытаюсь создать функцию, которая позволяет мне создать человека из значений followgin json, используя значения по умолчанию, когда отсутствует какой-либо параметр

{ "name": "john", "surname": "doe" }
{ "surname": "doe" }
{ "name": "john" }
{ }

Вот почему я ищу более общий способ справиться с этим.

(Я покажу некоторый псевдо-код, чтобы дать представление о том, чего я пытаюсь достичь)

Я думал о чем-то вроде:

val p = Person(name= "new person name", surname= Unit)

И в этом случае фамилия должна получить значение по умолчанию

Или что-то вроде

val p = Person( Map( "name" -> "new person name" ) _* )

Так что он также принимает значение по умолчанию для фамилии

Или, может быть, это сделать в конструкторе, если я обнаруживаю нулевое значение (или None), я мог бы присвоить значение по умолчанию.

На самом деле я пытаюсь избежать повторения определения значений по умолчанию.

Во всяком случае, какой был бы самый идиоматический способ достичь такого?

4b9b3361

Ответ 1

Если вы хотите использовать значение по умолчанию, вы обычно просто оставляете этот именованный аргумент:

scala> val p = Person(name = "new person name")
p: Person = Person(new person name,no surname)

Но, поскольку вы хотите явно знать, должно ли значение быть отменено по умолчанию или нет, вы можете реализовать свою идею на основе карты в конструкторе. Если вы не хотите повторять настройки по умолчанию, как насчет этих двух параметров:

Вариант 1: Внешние константы для значений по умолчанию

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

val nameDefault = "no name"
val surnameDefault = "no surname"

case class Person(name: String = nameDefault, surname: String = surnameDefault) {
  def this(m: Map[String, String]) =
    this(m.getOrElse("name", nameDefault), m.getOrElse("surname", surnameDefault))
}

Использование:

new Person(name = "new person name", surname = "new person surname")
new Person(Map("name" -> "new person name"))
new Person(name = "new person name")

Вариант 2: дополнительный альтернативный конструктор

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

case class Person(name: String, surname: String) {
  def this(name: Option[String] = None, surname: Option[String] = None) =
    this(name.getOrElse("no name"), surname.getOrElse("no surname"))

  def this(m: Map[String, String]) = this(m.get("name"), m.get("surname"))
}

Использование:

new Person(name = "new person name", surname = "new person surname")
new Person(Map("name" -> "new person name"))
new Person(name = Some("new person name"))
new Person(name = "new person name") // can't do this

Ответ 2

Я думаю, что это может быть проблемой для Либо. Вы можете указать Либо с двумя типами.

val name: Eiter[String, Unit] = Left("name")
val surname: Either[String, Unit] = Right( () )

Теперь вы можете проверить, есть ли у вас Left или Right и вызвать конструктор с необходимыми аргументами.