带有映射参数的 scala 案例类复制方法



我来自Java背景,我开始学习Scala。

我创建了一个类Foo,其中包含一个 Map[String,String] 和一个 add 方法。此方法只是将元素添加到映射并返回一个Foo对象,以便我可以使用链接。我正在尝试以"Scala 方式"执行此操作,以便我尝试返回一个包含新添加元素的新 Map 的副本,而不是向 Map 添加元素并返回相同的对象(key -> value)

case class Foo(map : Map[String, String]) {
def add(key:String, value:String) : Foo = copy(map = map ++ Map(key -> value))
}
object Foo{
def apply(): Foo = new Foo(Map.empty[String, String])
}

但是当我尝试向我的 Foo 类添加多个元素时,地图仍然是空的。

scala> f.add("Oi", "Hello")
res1: Foo = Foo(Map(Oi -> Hello))
scala> f.add("Tchau", "Bye")
res2: Foo = Foo(Map(Tchau -> Bye))
scala> f.map
res3: Map[String,String] = Map()

我做错了什么?

提前致谢

调用add时不会修改f。相反,您正在创建 Foo 的新实例。问题是你没有把它存储在任何地方。尝试:

> val g = f.add("Oi", "Hello")
> val h = f.add("Tchau", "Bye")
> h.map

澄清一下:当您调用add时,您实际上返回的不是相同的f实例,而是一个新实例。

如果要返回相同的实例,则需要可变的东西。

// make the reference mutable
case class Foo(var map : Map[String, String]) {
def add(key:String, value:String) : Foo = {
map = map ++ Map(key -> value))
this
}
}

// make the map mutable
case class Foo(map : scala.collection.mutable.Map[String, String]) {
def add(key:String, value:String) : Foo = {
map.updated(key, value)
this
}
}

澄清一下,您的解决方案是Scala 方式,即尽可能避免可变状态

唯一的改进是如Miguel所述,只添加一个条目(map + (key -> value)而不是整个地图 (map ++ Map(key -> value)(:

case class Foo(map : Map[String, String]) {
def add(key:String, value:String) : Foo = copy(map = map + (key -> value))
}
object Foo{
def apply(): Foo = new Foo(Map.empty[String, String])
}

拥有不可变值的美妙之处在于,没有人会更改您的实例。

所以例如:

val f = Foo()                   // -> Foo(Map())
val g = f.add("key1", "value1") // -> Foo(Map(key1 -> value1))
val h = g.add("key2", "value2") // -> Foo(Map(key1 -> value1, key2 -> value2))
f != g != h

这里的 Scala 方法是流畅地使用它:

Foo()
.add("key1", "value1")
.add("key2", "value2")
.add("key3", "value3") 

最新更新