2013-01-07 132 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表現懲罰)。 現在不是線程安全的。