withDefaultValue 以防 class

withDefaultValue in case class

简单案例class:

case class country(name: String, townPopulation: Map[String,Int])

简单的例子:

scala> val germany = country("Germany",Map("Berlin" -> 100000, "Saale" -> 4000))
germany: country = country(Germany,Map(Berlin -> 100000, Saale -> 4000))

scala> germany.townPopulation("Berlin")
res77: Int = 100000

scala> germany.townPopulation("blergh")
java.util.NoSuchElementException: key not found: blergh
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:59)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:59)
  ... 42 elided

我想 return 0 对于不存在的城镇,这可以在声明 val 时完成:

scala> val germany = country("Germany",Map("Berlin" -> 100000, "Saale" -> 4000).withDefaultValue(0))
germany: country = country(Germany,Map(Berlin -> 100000, Saale -> 4000))

scala> germany.townPopulation("fdhjkjhkhjdfg")
res79: Int = 0

但我无法弄清楚如何在一个地方做到这一点,至少在这种情况下不会 class,我想要一些简单的东西,如下所示,但我显然做错了:

scala> case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))
<console>:1: error: ')' expected but '.' found.
case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))
                                                                ^
<console>:1: error: ';' expected but ')' found.
case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))

是否有一条通向默认值始终为 0 的解决方案的简单路径?

使用 map.get(),其中 returns 一个 Option:

println germany.townPopulation.get("blergh").getOrElse(0)
// or, more concisely:
println germany.townPopulation.getOrElse("blergh", 0)

啊,在重新阅读你的问题时,你想在案例 class 中硬编码默认值。我想你得弄乱 apply() 方法。

val germany = country("Germany",
                      Map("Berlin" -> 100000, "Saale" -> 4000)
                        .withDefaultValue(0))

编辑(在 OP 回答后):

我的错!应该更彻底地阅读你的问题。

this SO question 所述:您无法选择更改默认构造函数存储其参数的方式(例如,在将参数存储为 vals 之前修改参数)[... ].

另一种解决方案是声明一个正则 class 及其 伴随对象 :

class Country(val name: String, val townPopulation: Map[String, Int])
case object Country {
  def apply(name: String, townPopulation: Map[String, Int]) =
    new Country(name, townPopulation.withDefaultValue(0))
}

这将允许您使用漂亮的语法声明国家/地区:

val germany = Country("Germany", Map("Berlin" -> 100000, "Saale" -> 4000))
assert(germany.townPopulation("Berlin") == 100000)
assert(germany.townPopulation("Blergh") == 0)

但请注意,由于 不是 case class,您将无法获得通常的 case class 津贴,例如:

// Compiler will give you
//    "object Country is not a case class,
//     nor does it have an unapply/unapplySeq member"
//germany match {
//  case Country(a, b) => println("It won't compile! Not a case class")
//}

根据您的用例,您可以走很长的路,并实施方法 unapplyunapplySeq 以在需要时检索此类行为!

我看到几种可能的方法:

  • 增加封装默认值逻辑的辅助方法

    def population(town : String) : Int = townPopulation.getOrElse(town, 0)

  • 将方法添加到具有相同目的的伴随对象

    def withDefault(name: String, townPopulation: Map[String, Int]) : country = country(name, townPopulation.withDefaultValue(0))