Scala-эквивалент статической переменной C ++ в функции

Я довольно новичок в Scala и наткнулся на следующую проблему:

что эквивалентно Scala статической переменной функции?

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

РЕДАКТИРОВАТЬ:

Я хочу добиться своего рода счетчика вызовов функций — я хочу проверить, сколько раз выполнялась моя функция, и в то же время ограничить видимость этого счетчика, чтобы его нельзя было изменить извне.

6

Решение

Вот блок кода, который имеет похожий эффект:

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;
}
18

Другие решения

Scala не имеет эквивалента локальным статическим переменным C ++. В Scala правила области видимости более согласованы, чем в C ++ или Java — то, что определено в блоке, выходит из области действия при выходе из блока. Как отмечали другие, локальная статическая переменная будет побочный эффект, что не желательно в функциональном программировании.

Scala, будучи гибридным ОО / функциональным языком, позволяет писать в императивном стиле, но предпочитает и поощряет функциональный стиль (например, делая неизменяемые коллекции выбором по умолчанию). Локальные статические переменные, помимо представления побочного эффекта как такового, также отсутствуют в Java, что является еще одной причиной, по которой они не предоставляются в Scala.

2

Чтобы получить эквивалент локальной статической переменной C ++ в 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
}

Тогда в методе:

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

Это будет работать так же, как в c ++, в том числе, когда метод или экземпляр класса-владельца выходят из области видимости (хотя и с ухудшением производительности).
Не потокобезопасен, как он стоит.

1
По вопросам рекламы [email protected]