Stufe 2Sprachkern · Lektion 6 von 34
Variablen, Werte und Basistypen
In Scala gibt es zwei Arten, einem Namen einen Wert zu geben: val für Werte, die sich nie ändern, und var für Variablen. Dazu kommen die Basistypen für Zahlen, Zeichen und Wahrheitswerte – und ein paar Eigenheiten beim Rechnen.
val und var
val pi = 3.14159 // unveränderlich
var zaehler = 0 // veränderlich
zaehler = zaehler + 1 // erlaubt
// pi = 3.0 // Fehler: Reassignment to val piEin val ist wie final in Java: Der Name ist fest an einen Wert gebunden. Eine var kann später neu belegt werden. In idiomatischem Scala ist val der Normalfall. Warum? Werte, die sich nicht ändern, sind leichter nachzuvollziehen, lassen sich gefahrlos zwischen Threads teilen und machen Fehler wie „wer hat diese Variable verändert?“ unmöglich.
Typinferenz und Typangaben
Im Beispiel oben steht nirgends ein Typ – der Compiler leitet ihn aus dem Wert ab. Sie können ihn aber jederzeit angeben:
val anzahl: Int = 42
val preis: Double = 9.99
val name: String = "Ada"
val aktiv: Boolean = trueEine Typangabe ist sinnvoll, wenn der abgeleitete Typ nicht der gewünschte ist, etwa val x: Long = 5 statt Int.
Die Basistypen
| Typ | Beschreibung | Beispiel |
|---|---|---|
Byte, Short | ganze Zahlen mit 8 bzw. 16 Bit | val b: Byte = 12 |
Int | ganze Zahl, 32 Bit | 42 |
Long | ganze Zahl, 64 Bit | 42L |
Float | Gleitkommazahl, 32 Bit | 3.5f |
Double | Gleitkommazahl, 64 Bit | 3.5 |
Char | einzelnes Zeichen | 'a' |
Boolean | Wahrheitswert | true, false |
String | Zeichenkette (aus Java) | "Hallo" |
Unit | „kein Wert“ | () |
Anders als in Java gibt es keine primitiven Typen, die sich anders verhalten als Objekte: Auch Int hat Methoden, etwa 5.max(9) oder -3.abs. Der Compiler übersetzt sie trotzdem, wo möglich, in schnelle primitive JVM-Werte. Wie die Typen zusammenhängen, zeigt die Hierarchie:
Rechnen mit Zahlen
val a = 7 / 2 // 3 – ganzzahlige Division
val b = 7 / 2.0 // 3.5 – sobald ein Double beteiligt ist
val c = 7 % 2 // 1 – Rest
val d = math.pow(2, 10) // 1024.0
val e = math.sqrt(2) // 1.4142135623730951
val f = BigDecimal("0.1") + BigDecimal("0.2") // exakt 0.3Zwei Eigenheiten, die Einsteiger regelmäßig überraschen:
- Überlauf:
Int.MaxValue + 1ergibt-2147483648, ohne Fehlermeldung. Für große Zahlen gibt esLongundBigInt. - Gleitkomma-Ungenauigkeit:
0.1 + 0.2ergibt0.30000000000000004. Für Geldbeträge nehmen SieBigDecimaloder rechnen in Cent mitLong.
Das Objekt math bündelt mathematische Funktionen wie sin, log, round und floor. Umwandlungen zwischen Zahltypen erledigen Methoden wie toInt, toDouble oder toLong: 3.9.toInt ergibt 3 (es wird abgeschnitten, nicht gerundet).
lazy val
Ein lazy val wird erst beim ersten Zugriff berechnet und danach zwischengespeichert:
lazy val konfiguration =
println("lese Datei …")
scala.io.Source.fromFile("app.conf").mkString
// noch nichts passiert
println(konfiguration.length) // jetzt wird gelesen
println(konfiguration.length) // jetzt nicht mehrDas lohnt sich für teure Berechnungen, die vielleicht gar nicht gebraucht werden.
Schlüsselwörter
Einige Wörter sind reserviert und dürfen nicht als Namen verwendet werden, darunter val, var, def, class, object, trait, if, else, match, case, for, while, yield, new, this, type, import, package und return. Scala 3 hat weitere „weiche“ Schlüsselwörter wie given, using, extension, end oder opaque, die nur an bestimmten Stellen eine Sonderbedeutung haben. Wer einen reservierten Namen trotzdem braucht, etwa für eine Java-Methode namens type, setzt ihn in Backticks, also in Gravis-Zeichen vor und hinter dem Namen.