2013-01-07 28 views
6

Sono abbastanza nuovo a Scala e ci siamo imbattuti seguente problema:Scala equivalente della variabile statica C++ in una funzione

ciò che è Scala equivalente della variabile statica della funzione?

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

EDIT:

Quello che voglio ottenere è una sorta di contatore chiamata di funzione - Voglio verificare quante volte è stata eseguita la mia funzione e nello stesso tempo limitare il visibilità di questo contatore in modo che non possa essere modificato dall'esterno.

+2

Potresti descrivere perché fai 'x' statico? Vi si può accedere da fuori di 'foo'? 'Foo' può essere ricorsivo? Non ho molta familiarità con C++ e sapendo che la tua intenzione renderà più facile creare uno snippet di codice Scala corrispondente. –

+2

La programmazione funzionale pura evita questo tipo di variabile mutabile perché porta a una funzione che non è "trasparente". – Mik378

+4

Lato C++: questo è noto come statico locale, la variabile è * globale * in quanto esiste una sola istanza in tutto il programma, tuttavia la sua visibilità (ambito lessicale) è limitata al corpo della funzione. Questo idioma può essere usato per implementare singleton, per esempio. –

risposta

18

Ecco un blocco di codice che ha effetto simile:

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 

Anche se devo sottolineare che questa è una pessima pratica dal momento che uccide referential transparency.

Se davvero bisogno di questo comportamento considerare questo:

type State = Int 

def f(state: State) = { 
val newState = state + 1 
println(state); 
newState; 
} 
+1

Questo (il primo esempio) è in realtà più simile a un funtore C++, ma si comporta effettivamente come se f() 'avesse una variabile statica locale. –

+1

Questo non deve necessariamente eliminare la trasparenza referenziale. Memoization viene in mente. – ebruchez

2

Scala non ha equivalenti alle variabili statiche locali di C++. In Scala, le regole di scoping sono più coerenti rispetto a C++ o Java - ciò che viene definito all'interno di un blocco, esce dall'ambito di applicazione quando il blocco viene chiuso. Come altri hanno notato, una variabile statica locale sarebbe un effetto collaterale , che non è auspicabile nella programmazione funzionale.

Scala, essendo un linguaggio OO/funzionale ibrido, consente di scrivere in stile imperativo, ma preferisce e incoraggia lo stile funzionale (ad esempio rendendo le raccolte immutabili la scelta predefinita). Le variabili statiche locali, oltre a rappresentare un effetto collaterale di per sé, sono assenti anche in Java, che è un motivo in più per non fornirle in Scala.

1

Per ottenere l'equivalente di un C++ variabile statica locale a Scala:

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 
} 

Poi nel metodo:

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

Funzionerà esattamente come in C++, anche quando il metodo o proprietario dell'istanza di classe non rientra nello scope (anche se w con una penalità di prestazioni). Non protetto da thread così com'è.

Problemi correlati