2

这个问题有点理论化。我有一个对象,其中包含一个私有可变列表或映射,其增长仅是附加的。我相信我可以争辩说对象本身是功能性的,在功能上是透明的,并且对于所有外观而言,是不可变的。所以例如我有

import scala.collection.mutable.Map

case class Foo(bar:String)

object FooContainer {
  private val foos = Map.empty[String, Foo]

  def getFoo(fooName:String) = foos.getOrElseUpdate(fooName, Foo(fooName))
}

我可以用列表做一个类似的案例。现在我想象要真正发挥功能,我需要确保线程安全,我想我可以简单地使用锁、同步或原子引用来做到这一点。我的问题是这一切都是必要的和充分的,这是一种常见的做法,这种行为是否有既定的模式?

4

2 回答 2

2

我会说“功能”确实是错误的术语。上面显示的确切示例可以称为“纯”,因为它的输出仅由其输入定义,因此没有任何(可见的)副作用。但实际上它是不纯的,因为它具有隐藏的内部状态。

给定相同的参数值,该函数始终评估相同的结果值。函数结果值不能依赖于任何可能随着程序执行或程序的不同执行而改变的隐藏信息或状态,也不能依赖于来自 I/O 设备的任何外部输入。维基百科

但是,如果您使Foo类可变,那么明显的杂质就会消失:

case class Foo(bar:String) {
    private var mutable:Int = 1
    def setFoo(x:Int) = mutable = x
    def foo = mutable
}

类的可变性Foo导致getFoo不纯:

scala> FooContainer.getFoo("test").foo
res5: Int = 1

scala> FooContainer.getFoo("bla").setFoo(5)

scala> FooContainer.getFoo("bla").foo
res7: Int = 5

为了使函数看起来是纯的,FooContainer.getFoo("bla").foo必须始终返回相同的值。因此,所描述的构造的“纯度”充其量是脆弱的。

于 2013-03-12T11:39:30.047 回答
1

作为一般规则,与持有可变类型var相比,持有不可变集合类型会在更新时被替换,这会更好。val前者从不处理创建后可能发生变化的值(除了拥有不断变化的值本身的类)。然后,您只需要适度注意何时将更新的值var发布给它,但是由于更新引用通常是原子的(除了在 32 位机器上将 along或 a存储到 RAM 之类的事情),几乎没有风险double.

于 2013-03-12T16:39:34.197 回答