我来自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")