vir*_*yes 23 scala mutable map use-case immutability
我目前的用例非常简单,无论是可变的还是不可变的Map都可以解决问题.
有一个采用不可变Map的方法,然后调用第三方API方法,该方法也采用不可变Map
def doFoo(foo: String = "default", params: Map[String, Any] = Map()) {
val newMap =
if(someCondition) params + ("foo" -> foo) else params
api.doSomething(newMap)
}
Run Code Online (Sandbox Code Playgroud)
有问题的地图通常很小,最多可能有一个嵌入的案例类实例列表,最多几千个条目.因此,再次假设在这种情况下对于不可变的影响很小(即通过newMap val副本基本上有2个Map实例).
不过,它让我有点唠叨,复制地图只是为了得到一张新的地图,上面贴着几个k-> v条目.
我可以params.put("bar", bar)为我想要处理的条目变为可变等等,然后params.toMap为api调用转换为immutable,这是一个选项.但后来我必须导入并传递可变映射,与使用Scala的默认不可变映射相比,这有点麻烦.
那么,对于在不可变映射上使用可变映射的合理/良好实践的一般指导原则是什么?
谢谢
编辑 所以,看起来不可变地图上的添加操作接近恒定时间,确认@ dhg和@Nicolas断言没有制作完整副本,这解决了所呈现的具体案例的问题.
dhg*_*dhg 36
根据不可变的Map实现,添加一些条目可能实际上不会复制整个原始Map.这是不可变数据结构方法的优势之一:Scala将尽可能少地尝试复制.
这种行为最容易看到List.如果我有val a = List(1,2,3),那么该列表存储在内存中.但是,如果我在前面加上一个额外的元素一样val b = 0 :: a,我也得到一个新的4元List回来,但斯卡拉并没有复制一部开拓创新的列表a.相反,我们只创建了一个名为它的新链接,b并为其指定了现有List a.
您也可以为其他类型的集合设想这样的策略.例如,如果我向a添加一个元素Map,则集合可以简单地包装现有映射,在需要时回退到它,同时提供API就好像它是单个映射一样Map.
par*_*tic 14
使用可变对象本身并不坏,它在函数式编程环境中变得很糟糕,在这种环境中,你试图通过保持函数纯和对象不可变来避免副作用.
但是,如果在函数内创建可变对象并修改此对象,则如果不在函数外部释放对该对象的引用,则该函数仍然是纯的.可以使用以下代码:
def buildVector( x: Double, y: Double, z: Double ): Vector[Double] = {
val ary = Array.ofDim[Double]( 3 )
ary( 0 ) = x
ary( 1 ) = y
ary( 2 ) = z
ary.toVector
}
Run Code Online (Sandbox Code Playgroud)
现在,我认为这种方法在两种情况下是有用/推荐的:(1)性能,如果创建和修改不可变对象是整个应用程序的瓶颈; (2)代码可读性,因为有时更容易修改复杂的对象(而不是诉诸镜头,拉链等)