Scala:如何使用默认值初始化对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10472758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala: how to initialize an object using default values
提问by opensas
I think this will be better explained with an example
我认为这会用一个例子更好地解释
I have the following case class
我有以下案例类
case class Person(name: String = "no name", surname: String = "no surname")
And I want to make a general function to populate it from, for example, a json message, that might not specify all fields
而且我想创建一个通用函数来填充它,例如,可能未指定所有字段的 json 消息
I know that to use the default values the simple answer is not to pass them to the constructor, but if I have several fields that may or may not appear in the json, I should have to use a huge switch sentence covering every possible combination of missing parameters. In this case, after reading the json, I should take care of name & surname present, no name, no surname and no name nor surname case... (Gee, I hope I made myself clear).
我知道要使用默认值,简单的答案是不要将它们传递给构造函数,但是如果我有几个字段可能会或可能不会出现在 json 中,我应该使用一个巨大的 switch 语句来覆盖所有可能的组合缺少参数。在这种情况下,在阅读json之后,我应该注意name & surname present, no name, no surname and no name and surname case...(哎呀,我希望我说清楚了)。
To be more precise, I'm trying to develop a function that allows me to create a person from the following json values, using the default values when there's some parameter missing
更准确地说,我正在尝试开发一个函数,允许我从以下 json 值创建一个人,当缺少某些参数时使用默认值
{ "name": "john", "surname": "doe" }
{ "surname": "doe" }
{ "name": "john" }
{ }
That's why I'm looking for a more general way to handle this.
这就是为什么我正在寻找一种更通用的方法来处理这个问题。
(I'll show some pseudo code to give and idea of what I'm trying to achieve)
(我将展示一些伪代码来给出我想要实现的目标)
I was thinking about something like:
我在想类似的事情:
val p = Person(name= "new person name", surname= Unit)
And in that case surname should get the default value
在这种情况下,姓氏应该获得默认值
Or something like
或者类似的东西
val p = Person( Map( "name" -> "new person name" ) _* )
So that it also takes the default value for surname
以便它也采用姓氏的默认值
Or maybe doing it in the constructor, if I detect a null value (or None) I could assign the default value.
或者也许在构造函数中这样做,如果我检测到空值(或无),我可以分配默认值。
In fact, I'm trying to avoid repeating the definition of the default values.
事实上,我试图避免重复默认值的定义。
Anyway, what would be the most idiomatic way to achieve such a thing?
无论如何,实现这一目标的最惯用的方法是什么?
回答by dhg
If you want the default value to be used, you normally just leave off that named argument:
如果您想使用默认值,通常只需省略该命名参数:
scala> val p = Person(name = "new person name")
p: Person = Person(new person name,no surname)
But, since you want to explicitly know whether a value should be defaulted or not, you could implement your Map-based idea in a constructor. If you don't want to repeat the defaults, how about these two options:
但是,由于您想明确知道一个值是否应该被默认,您可以在构造函数中实现您的基于 Map 的想法。如果您不想重复默认值,那么这两个选项如何:
Option 1: Externalized constants for defaults
选项 1:默认值的外部化常量
Set the defaults externally. Use them in both the main constructor and the Map-based constructor.
在外部设置默认值。在主构造函数和基于 Map 的构造函数中使用它们。
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))
}
Usage:
用法:
new Person(name = "new person name", surname = "new person surname")
new Person(Map("name" -> "new person name"))
new Person(name = "new person name")
Option 2: Optionified alternate constructor
选项 2:可选的替代构造函数
You may find this a little cleaner since it doesn't rely on externalized constants. The only downside here is that if you want to construct with only some of the parameters, you have to wrap each one in Some().
您可能会发现这更简洁一些,因为它不依赖于外部常量。这里唯一的缺点是,如果您只想使用某些参数进行构造,则必须将每个参数都包装在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"))
}
Usage:
用法:
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
回答by tgr
I think this might be a usecase for Either. You can specify an Either with two types.
我认为这可能是Either 的一个用例。您可以指定具有两种类型的任一类型。
val name: Eiter[String, Unit] = Left("name")
val surname: Either[String, Unit] = Right( () )
Now you can check whether you have a Left or a Right and call the constructor with the arguments you want.
现在你可以检查你是否有一个 Left 或一个 Right 并用你想要的参数调用构造函数。

