Variable
Stand: 27. Mai 2013
Einstieg
Die Deklaration einer Variable beginnt mit den Schlüsselwörtern
var, val
oder lazy val
. Anschließend wird
durch einen Doppelpunkt getrennt der Typ der Variablen angegeben. Nach der
Typangabe kann/muss nach einem Gleichheitszeichen "=" eine
Wertzuweisung erfolgen.
var auto: String = "BMW" val name1: Int = 3 lazy val calcuated: Int = 23*63+3
Mit dem Schlüsselwort var
werden Variable definiert,
deren Wert beliebig oft verändert werden kann. Dementgegen werden mit dem
Schlüsselwort val
unveränderliche Variablen
definiert. Nach der ersten Zuweisung (bei der Deklaration) kann eine unveränderliche Variable nicht mehr
verändert werden. Die Zuweisung der val
-Variablen einer
Klasse erfolgt bei dessen ersten Verwendung.
Mit den beiden Schlüsselwörtern
lazy val
werden auch unveränderliche Variable definiert,
deren Wertezuweisung erst dann erfolgt, wenn die Variable zum ersten Mal verwendet
wird. Dies ist z.B. sinnvoll, wenn die Belegung einer Variablen mit einer
zeitaufwendigen Berechnung erfolgt und jedoch es nicht sicher ist, dass die
Variable überhaupt verwendet wird.
Für die funktionale Programmierung mit Scala gilt, dass wen möglich,
unveränderliche Variablen (also mit val
definiert) verwendet
werden. Ein Vorteil dieser Vorgehensweise liegt in der nebenläufigen Programmierung.
Wenn Variablen sich nicht verändern können, besteht auch nicht das
Problem der race condition1. Die aufwendige
Synchronisation des Variablenzugriff entfällt damit in Scala.
Typableitung (engl. type inference)
In Scala braucht man meist nicht anzugeben, von welchem Typ
eine Variable ist.
Der Scala Compiler ist meistens in der Lage
den Typ einer Variablen aus dem umgebenden Kontext abzuleiten
und verzichtet darauf, dass dieser expliziert angegeben wird.
Sieht man sich folgende Variablendefinition an, ist sofort klar,
dass es sich um eine Int
Variable handeln muss.
Da auch der Compiler dies so erkennt, muss der Typ nicht explizit
angegeben werden.
val myInt = 42
Da oft die Typangaben bei der Variablendefinition fehlen, sieht Scala Quelltext oft aus als handele es sich um eine dynamisch typisierte Sprache, was Scala definitiv nicht ist.
Variablen Sichtbarkeit (engl. Scope)
In Scala können wir, wie bei den meisten anderen Programmiersprachen, nicht von jeder beliebigen Stelle im Quelltext auf eine Variable zugreifen. Um auf eine Variable zugreifen zu können, muss diese sich im Sichtbarkeitsbereich der entsprechenden Quelltextstelle befinden. Der Sichtbarkeitsbereich einer Variablen wird englischsprachig als Scope bezeichnet.
Beschäftigen wir uns zunächst auf den Variablenzugriff innerhalb derselben
Klasse (gilt analog für im selbigen object
). Um auf eine Variable zugreifen
zu können, muss diese vor der zugreifenden Stelle definiert worden sein. Eine weitere
Vorgabe ist, dass die Variablendefinition im Gleichen oder einen "höheren",
umgebenen Block erfolgte.
Nachfolgend Beispiele zum Variablen-Scope.
class Scope1 { def method1(): Unit = { println(myValue) // Error val myValue = 4 println(myValue) // OK } }
Das Beispiel Scope1 zeigt, dass eine Variable zunächst definiert werden
muss, bevor auf Sie zugegriffen werden kann.
Die Variable myValue
wird in Zeile 4 definiert. Somit ist der
Zugriff in Zeile 3 ein Fehler, wohingegen der Zugriff in Zeile 5 in Ordnung
ist.
Überschatten
In Scala können Variablen in einem tieferliegenden Block, Variable eines höher liegenden Blockes überschatten. Dies geschieht, wenn die Variable im tiefer liegenden Block den gleichen Namen hat, wie der Name der Variable im höher liegenden Block.
object Scope3 { def main(args: Array[String]): Unit = { val a = 4 println(a) { val a = 5 println(a) } println(a) } }
Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:
4 5 4
Eine weitere Form des Überschattens ist das Überschatten von Variablen einer
Basisklasse. Dies geschieht, indem in der Subklasse eine Variable mit dem Namen
der zu überschattenden Basisklassen-Variable definiert wird. Wenn wir eine
Basisklassen-Variable überschatten wollen, müssen wir der Variablen-Definition
ein override
voranstellen. Dies gibt an, dass wir explizit eine
Basisklassen-Variable überschatten wollen und führt zu einem Fehler,
sofern wir keine Basisklassen-Variable überschatten.
Das nachfolgende Beispiel zeigt das Überschatten einer Basisklassen-Variable.
object Test { def main(args: Array[String]): Unit = { val myA = new A val myB = new B println(myA.aValue) println(myB.aValue) } } class A { val aValue = 42 } class B extends A { override val aValue = 43 }
Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:
42 43
1 Unter race condition versteht man das Problem, das zwei oder mehrere threads unsynchronisiert auf gleiche Variablen lesend und schreibend zugreifen.