在Scala中是否有一种方法可以删除可变变量,或者将可变变量保留在下面的情况下可以吗?

时间:2013-05-30 21:08:40

标签: scala immutability mutability

我知道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)。这是合法的还是仍然有一些不可改变的方式来处理它?<​​/ p>

5 个答案:

答案 0 :(得分:0)

无论何时存储状态,您都需要使用可变性。

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

如果你真的希望 compute 的类是不可变的,那么其他一些可变类需要包含 x ,它需要传递给compute方法

答案 1 :(得分:0)

  

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

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

答案 2 :(得分: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。有了“命令性”背景,你不要指望队列是不可变的。

因此,如果你看一下你的模式,很可能你可以把它变成不可变的。

答案 3 :(得分:0)

我会创建一个不可变的A类(这里是一个case类),让一个对象处理可变性。对于每个状态更改,我们创建一个新的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*/ }
}

答案 4 :(得分:0)

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

每次修改/更改/更新/变异变量时,处理此变量的必要方法是使用该变量记录此类变更。功能性思维方式是使活动(导致变化)为您带来新的状态。换句话说,它就像是因果效应。功能性思维方式侧重于因果关系的过渡活动。

鉴于这一切,在程序执行的任何给定时间点,我们的成就是中间结果。无论我们如何做,我们都需要在某处保持结果。这样的中间结果是状态,是的,我们需要一些变量来保持它。这就是我想用抽象思维分享的东西。