我对Scala很陌生,偶然发现以下问题:
什么是Scala相当于函数的静态变量?
void foo()
{
static int x = 5;
x++;
printf("%d", x);
}
编辑:
我想要实现的是一种函数调用计数器 - 我想检查我的函数执行了多少次,并且同时限制了这个计数器的可见性,以便它不能从外部修改。
答案 0 :(得分:18)
这是一段具有类似效果的代码:
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
虽然我必须强调这是一种非常糟糕的行为,因为它会杀死referential transparency。
如果你真的需要这种行为,请考虑这个:
type State = Int
def f(state: State) = {
val newState = state + 1
println(state);
newState;
}
答案 1 :(得分:2)
Scala与C ++的本地静态变量没有相同之处。在Scala中,作用域规则比C ++或Java更加一致 - 块中定义的内容在退出块时超出范围。正如其他人所指出的,局部静态变量将是副作用,这在函数式编程中是不可取的。
Scala是一种混合的OO /函数式语言,它可以用命令式的方式编写,但更喜欢并鼓励功能风格(例如,通过使不可变集合成为默认选择)。除了表示副作用本身之外,本地静态变量在Java中也不存在,这是在Scala中不提供它们的另一个原因。
答案 2 :(得分: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 ++中一样,包括当方法或拥有类实例超出范围时(尽管还有性能损失)。 现在不是线程安全的。