3

我了解 Scala 完全包含不变性。

现在我在想一个场景,我必须在一个类等中保持一些状态(通过变量)。稍后我需要更新这些变量;然后我可以稍后重新访问该类以访问更新的变量。

我将尝试通过一个非常简单的示例使其变得简单:

class A {
  var x: Int
  def compute: Int = {calling some other processes or such using x as input}
}

……

def invoker() {
  val a: A = new A
  a.x = 1
  ......
  val res1 = a.compute
  a.x = 5
  ......
  val res2 = a.compute
  ......
}

所以你看,我需要不断改变 x 并得到结果。如果您认为我可以简单地将 x 作为计算的参数,例如

def compute(x: Int) 
......

这是个好主意,但在我的情况下我不能这样做,因为我需要将 x 的设置值分开并完全计算结果。换句话说,设置 x 值不应该触发“计算”发生,相反,我需要能够在程序中随时设置 x 值,并且能够在程序中的任何其他时间重用该值进行计算,当我需要它时.

在这种情况下,我使用了一个变量 (var x: Int)。这是合法的还是仍然有一些不可变的方法来处理它?

4

5 回答 5

0

我会创建一个不可变的 A 类(这里是一个案例类)并让一个对象处理可变性。对于每个状态更改,我们创建一个新的 A 对象并更改对象中的引用。如果您从不同的线程设置 x,这会更好地处理并发性,您只需将变量设置为 volatile 或 AtomicReference。

object A {
    private[this] var a = A(0)
    def setX(x: Int) { if (x != a.x) a = new A(x) }
    def getA: A = a
}

case class A(x: Int) {
    def compute: Int = { /*do your stuff*/ }
}
于 2013-05-31T17:36:58.827 回答
0

相反,我需要能够在程序中随时设置 x 值,并且能够在需要时在程序中的任何其他时间重用该值进行计算。

然后,根据定义,您希望您的类是有状态的。您可以重组您的问题,以便特定类不需要状态,但是您必须弄清楚这是否有用和/或值得麻烦。

于 2013-05-30T21:45:58.077 回答
0

经过几个月的函数式编程,这是我的重新思考。

每次修改/更改/更新/突变变量时,处理此问题的必要方法是使用该变量记录此类更改。功能性的思维方式是让活动(导致变化)给你带来新的状态。换句话说,这就像因果关系的东西。功能性思维侧重于因果之间的转换活动。

鉴于所有这些,在程序执行的任何给定时间点,我们的成就都是中间结果。无论我们如何做,我们都需要在某个地方保存结果。这样的中间结果就是状态,是的,我们需要一些变量来保存它。这就是我想与抽象思维分享的内容。

于 2013-11-12T18:58:56.520 回答
0

任何时候存储状态都需要使用可变性。

在您的情况下,您希望分别存储x和计算。本质上,这意味着状态是必需的,因为计算的结果取决于x的状态

如果您真的希望具有计算的类是不可变的,那么其他一些可变类将需要包含x并且需要将其传递给计算方法。

于 2013-05-30T21:19:03.827 回答
0

您的模式ListBuffer用于例如(size作为您的compute功能)。

所以是的,在某些情况下,您可以出于充分的理由使用此模式。例子:

val l = List(1, 2, 3)

val lb = new ListBuffer[Int]
l.foreach(n => lb += n * n)
val result = lb.toList

println(result)

另一方面,缓冲区通常仅用于尽快创建不可变实例。如果您查看此代码,有两个项目可能表明它可以更改:可变缓冲区和foreach(因为foreach仅因其副作用而被调用)

所以另一种选择是

val l = List(1, 2, 3)

val result = l.map(n => n * n)

println(result)

在更少的行中做同样的事情。我更喜欢这种风格,因为您只是在查看不可变实例和“功能”函数。

在您的抽象示例中,您可以尝试将可变状态和函数分开:

class X(var i: Int)

class A {
  def compute(x: X): Int = { ... }
}

甚至可能

class X(val i: Int)

这种方式compute变得实用:它的返回值仅取决于参数。

关于“意想不到的”不可变类,我个人最喜欢的是scala.collection.immutable.Queue. 在“势在必行”的背景下,您不会期望队列是不可变的。

因此,如果您查看您的模式,您很可能可以将其更改为不可变的。

于 2013-05-31T07:07:31.447 回答