2013-01-07 159 views
6

C++静态变量的我是很新的Scala和跨以下问题跌跌撞撞:斯卡拉相当于一个功能

什么是Scala的功能的静态变量的相同呢?

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

编辑:

我想实现的是一种函数调用计数器 - 我要检查多少次,我的功能已被执行,并在同一时间限制该计数器的可视性使其不能从外部修改。

+2

你能描述一下为什么让'x'静态?它可以从'foo'之外访问吗? 'foo'可能是递归的?我对C++并不是很熟悉,并且知道你的意图会更容易想出一个相应的Scala代码片段。 –

+2

纯粹的函数式编程避免了这种可变变量,因为它导致了一个不“透明”的函数。 – Mik378

+4

C++方面:这被称为局部静态,变量是* global *,因为整个程序中只存在一个实例,但它的可见性(词法范围)限制在函数的主体中。例如,这个习语可以用来实现单身人士。 –

回答

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

这个(第一个例子)实际上更像是一个C++函数,但它的行为的确如'f()'有一个局部静态变量。 –

+1

这并不一定要杀死参照透明度。记忆在脑海中浮现。 – ebruchez

2

Scala没有等价于C++的本地静态变量。在Scala中,范围规则比C++或Java更加一致 - 在块中定义的内容在块被退出时超出范围。正如其他人所指出的,本地静态变量将是副作用,这在函数式编程中是不可取的。作为一种混合OO /函数式语言,Scala使写入命令式风格成为可能,但更喜欢和鼓励功能风格(例如通过使不可变集合成为默认选择)。除了代表副作用本身之外,本地静态变量在Java中也不存在,这是在Scala中不提供它们的另一个原因。

1

为了得到一个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++中一样工作,包括当方法或拥有的类实例超出范围时(尽管w表现惩罚)。 现在不是线程安全的。