9

我对 Scala 很陌生,偶然发现了以下问题:

Scala 等价于函数的静态变量是什么?

void foo()
{
    static int x = 5;
    x++;
    printf("%d", x);
}

编辑:

我想要实现的是一种函数调用计数器——我想检查我的函数已经执行了多少次,同时限制这个计数器的可见性,使其不能从外部修改。

4

3 回答 3

20

这是一个具有类似效果的代码块:

scala> object f extends Function0[Unit] {
     |   var x = 0;
     |   def apply = {
     |     x = x + 1;
     |     println(x);
     |   }
     | }
defined module f

scala> f()
1

scala> f()
2

尽管我必须强调这是一种非常糟糕的做法,因为它会破坏引用透明度

如果您真的需要这种行为,请考虑:

type State = Int

def f(state: State) = {
 val newState = state + 1
 println(state);
 newState;
}
于 2013-01-07T13:27:58.353 回答
3

Scala 没有等效于 C++ 的局部静态变量。在 Scala 中,范围规则比在 C++ 或 Java 中更一致——在块中定义的内容在退出块时超出范围。正如其他人指出的那样,局部静态变量会产生副作用,这在函数式编程中是不可取的。

Scala 是一种混合的面向对象/函数式语言,使得以命令式风格编写成为可能,但更喜欢并鼓励函数式风格(例如,通过将不可变集合作为默认选择)。局部静态变量,除了本身代表副作用之外,在 Java 中也没有,这是不在 Scala 中提供它们的另一个原因。

于 2013-01-07T13:27:05.787 回答
1

要在 Scala 中获得等效的 C++ 局部静态变量:

import scala.collection.parallel.mutable
import scala.reflect._
import scala.reflect.runtime.universe._

object StaticLocal {
  private val classes = new mutable.ParHashSet[String]
  private val variables = new mutable.ParHashMap[String, AnyVal]
}

import Numeric._

class StaticLocal[T <: AnyVal](value:T)(implicit tag: TypeTag[T], num: Numeric[T]){
  val name = this.getClass + "." + tag.toString() ;
  private var inited = false
  if (!inited) {
    inited = true

    if (!StaticLocal.classes.contains(name)) {
      StaticLocal.classes += name
      StaticLocal.variables += name -> value.asInstanceOf[AnyVal]
    }
  }
  def get():T = {StaticLocal.variables.get(name) match { case x:Some[Int] => (x.get).asInstanceOf[T] ; case None => throw new Exception("Not found:" + name) }}
  def set(value:AnyVal) { StaticLocal.variables.put(name, value)}
  def +(v:StaticLocal[T]):T = { num.plus(this.get, v.get)  }
  def +(v:T):T = { num.plus(this.get, v)  }
  def +=(v:T):Unit = { set(num.plus(this.get, v)) }
  def +=(v:StaticLocal[T]):Unit = { set(num.plus(this.get, v.get)) }

  override def toString() = { get.toString}
  implicit def StaticLocalWrapper(s: StaticLocal[T]):T = s.get
}

然后在方法中:

def foo():Unit
{
  object x extends StaticLocal( 5 )
  x += 1
  println( x )
}        

这将像在 c++ 中一样工作,包括当方法或拥有的类实例超出范围时(尽管还存在性能损失)。就目前而言,不是线程安全的。

于 2015-11-20T08:57:49.597 回答