A.2 Datentypen 

Anders als beispielsweise Java und C++ kennt Kotlin keine primitiven Datentypen. Die Anweisung println(1::class.simpleName) gibt deshalb »Int« aus. :: liefert die Referenz auf diejenige Klasse, die zur Laufzeit den Wert 1 repräsentiert.
A.2.1 Zahlen 

Tabelle A.1 zeigt die in Kotlin eingebauten Datentypen für ganze Zahlen. Vorzeichenlose Typen (sie beginnen mit U) wurden erst mit Kotlin 1.3 eingeführt. Zum Zeitpunkt der Drucklegung waren sie noch als experimentell gekennzeichnet.
Typ |
Bits |
Kleinster Wert |
Größter Wert |
---|---|---|---|
Byte |
8 |
–128 |
127 |
UByte |
8 |
0 |
255 |
Short |
16 |
–32.768 |
32.767 |
UShort |
16 |
0 |
65.535 |
Int |
32 |
–2.147.483.648 (–231) |
2.147.483.647 (231 – 1) |
UInt |
32 |
0 |
232 – 1 |
Long |
64 |
–9.223.372.036.854.775.808 (–263) |
9.223.372.036.854.775.807 (263 – 1) |
ULong |
64 |
0 |
264 – 1 |
Tabelle A.1 Ganzzahlige Datentypen
Gleitkommazahlen (Tabelle A.2) können in Kotlin zwei Genauigkeiten haben. Sie sind entweder 32 oder 64 Bit groß. Beim Inferieren wird Double angenommen. Soll ausdrücklich Float verwendet werden, muss dem Literal f oder F nachgestellt werden: val pi = 3.14f.
Typ |
Bits |
Signifikant |
Bit Exponent |
Dezimalstellen |
---|---|---|---|---|
Float |
32 |
24 |
8 |
6–7 |
Double |
64 |
53 |
11 |
15–16 |
Tabelle A.2 Gleitkommazahlen in Kotlin
Alle Datentypen bieten Konvertierungsfunktionen an. Beispielsweise liefert 3.14.toInt() das Ergebnis 3. Welche Umwandlungen möglich sind, hängt vom Datentyp ab. toString() steht immer zur Verfügung, da sie in der Wurzel des Kotlin-Typsystems definiert ist. Mehr dazu etwas später.
A.2.2 Zeichen und Zeichenketten 

Für einzelne Zeichen gibt es den Typ Char. Anders als beispielsweise in Java kann dieser nicht direkt als Zahl verwendet werden. Die Zeile
var a: Char = 65
ist ungültig und provoziert die Fehlermeldung »The integer literal does not conform to the expected type Char«. Für Literale werden einfache Hochkommata benutzt: 'a'. Häufige Escape-Sequenzen sind \t, \b, \n, \r, \', \", \\ und \$. Ein beliebiges 16-Bit-Unicodezeichen sprechen Sie mit '\u...' an. Der Ausdruck print('\u00a9') gibt das Copyright-Symbol aus. Allerdings lassen sich damit nicht beliebige Unicode-Codepunkte ansprechen. Hierfür brauchen wir einen weiteren Datentyp, String. Zeichenketten bestehen aus Chars und sind unveränderlich. Mit [] können Sie lesend auf eine bestimmte Position zugreifen. Die Länge wird mit length abgefragt. Für die Position gilt somit 0 <= pos < length. Vergleiche erfolgen mit == und !=. Weitere Informationen hierzu finden Sie in Abschnitt A.5.3, »Gleichheit und Identität«.
val s = "Hello, world!\n"
print(s[s.length - 1].toInt())
Jedes Unicodezeichen entspricht einem sogenannten Codepunkt. Der Smiley hat den hexadezimalen Wert 1F642. Character.toChars() liefert die enthaltenen Zeichen. Diese können dem String-Konstruktor übergeben werden (Listing A.5). Die Variable smiley besteht aus zwei Zeichen, aber nur einem Codepunkt. Sie können ihn mit codePointAt() ermitteln. Der Zugriff auf Codepunkte ist vermutlich nur in Ausnahmefällen nötig. In den meisten Fällen dürfte der Char-basierte Index ausreichend sein.
val codepoint = 0x1F642
val smiley = String(Character.toChars(codepoint))
println(smiley)
println("smiley.length: ${smiley.length}")
println("smiley.codePointCount(): ${smiley.codePointCount(0, smiley.length)}")
println(codepoint == smiley.codePointAt(0))
Listing A.5 Unicode-Codepunkte
Praktisch ist, dass Sie mit sogenannten Raw Strings Zeichenketten definieren können, die sich über mehrere Zeilen erstrecken und Sonderzeichnen enthalten, die sonst escaped werden müssten.
val text = """
for (c in "Kotlin")
print(c)
"""
println(text)
Listing A.6 Raw Strings
Ebenfalls äußerst nützlich sind String Templates. Sie ermöglichen das Erzeugen von Zeichenketten, die Werte von Variablen enthalten, ohne die in vielen anderen Programmiersprachen nötigen variablen Argumente für printf() und Co.
val i = 10
println("i = $i")
val s = "abc"
println("$s.length ist ${s.length}")
Listing A.7 String Templates
Um einfache Variablen anzusprechen, muss diesen nur ein $ vorangestellt werden. Soll das Ergebnis eines Ausdrucks oder Funktionsaufrufs integriert werden, wird der Ausdruck mit ${ ... } geklammert.
A.2.3 Wahrheitswerte 

Wahrheitswerte haben den Typ Boolean. Variablen können die Werte true und false annehmen. Die von Java bekannten Operatoren wie ||, && und ! können wie gewohnt verwendet werden.
val a = true
val b = false
println(a && b)
println(a && !b)
println(a || b)
Listing A.8 Wahrheitswerte in Kotlin
Alternativ können or und and verwendet werden. Allerdings werden Ausdrücke dann vollständig ausgewertet.
fun main() {
println(false && test())
println("---")
println(false and test())
}
fun test(): Boolean {
println("Hallo")
return false
}
Listing A.9 Unterschiede zwischen »&&« und »and«
and repräsentiert eine normale Funktion. Sie könnten deshalb alternativ auch println(false.and(test())) schreiben. Natürlich ist die Verwendung als Infix-Operator besser lesbar.
A.2.4 Felder 

Felder werden mit der Klasse Array abgebildet. Den Typ ihrer Elemente geben Sie mit < ... > an. arrayOf() initialisiert ein Feld mit einer übergebenen Liste. Alternativ können Sie dem Konstruktor einen Lambda-Ausdruck übergeben. Er wird für jeden Index einmal aufgerufen.
val intArray = arrayOf(1, 2, 3)
println(intArray[intArray.size - 1])
val ints = Array(4, { i -> i * i })
ints.forEach { println(it) }
Listing A.10 Felder initialisieren
Neben dem typisierten Array gibt es Spezialisierungen, beispielsweise IntArray und BooleanArray. Allerdings unterscheiden sich diese in ihrer Verwendung. Während val a: Array<Int> = arrayOf(1, 2) richtig ist, wird die Zeile val b: IntArray = arrayOf(1, 2) mit der Fehlermeldung »Type inference failed« quittiert. Sie müssen stattdessen intArrayOf(1, 2) verwenden. Grund hierfür sind unterschiedliche Datentypen zur Laufzeit. Array<Int> erzeugt Felder mit Int-Elementen, wohingegen IntArray Felder mit int (Javas primitiver Datentyp) entspricht.