Der Weg zum Erlernen von Scala führt in der Regel über die REPL. Dies ist eine sehr praktische Methode, um Funktionen, die Sie schreiben, einfach und schnell auszuprobieren, ohne eine ganze IDE-Umgebung einrichten zu müssen. Die neueste stabile Version von Scala ist Scala 2.7.5. Scala 2.8 wird in ein paar Monaten erscheinen, so wie es jetzt aussieht. Diese neue Version wird eine Reihe von Verbesserungen und neuen Funktionen enthalten, und wenn Sie es nicht abwarten können, sollten Sie den Stamm auschecken und verwenden. Ich habe bereits
Holen Sie sich den Trunk Um den Trunk zu verwenden, können Sie entweder die Quellen auschecken und ihn selbst bauen oder die nächtlichen Builds verwenden. Wahrscheinlich haben Sie eine SCALA_HOME-Umgebungsvariable gesetzt. Zeigen Sie also einfach auf den neu erstellten Build und starten Sie die REPL. Wenn alles gut gegangen ist, sollten Sie etwas wie das Folgende sehen:
Willkommen bei Scala Version 2.8.0.r18341-b20090718103640 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_14). Geben Sie Ausdrücke ein, damit sie ausgewertet werden. Geben Sie :help ein, um weitere Informationen zu erhalten. scala>
Wenn Sie den Stamm verwenden, können Sie als erstes von der neu gestalteten und verbesserten Scala-Sammlungsbibliothek profitieren. Sie wurde in großem Umfang neu gestaltet, größtenteils von Martin Odersky selbst. Sie wurde eingecheckt und befindet sich schon seit einiger Zeit im Stamm, so dass Sie bei der Verwendung des Stammes den Vorteil haben, mit ihr zu arbeiten. Die neue API wird im Scala Improvement Proposal erläutert, einer ausgezeichneten und unverzichtbaren Lektüre für das Verständnis des Designs der Scala-Sammlungen. Verwendung der überarbeiteten REPL Paul Phillips löst nicht nur einen Fehler nach dem anderen im Stamm, er hat auch die Angewohnheit, die REPL regelmäßig aufzumotzen. Ein sehr nettes Feature ist die Code-Vervollständigung, sehr praktisch, wenn Sie nicht die komplette Scala-API im Kopf haben. Definieren Sie zunächst eine Variable und drücken Sie nach der Eingabe der Variable (und möglicherweise des Beginns einer Funktion) die Tabulatortaste:
scala> val l = Liste(1,2,3) l: List[Int] = List(1, 2, 3) scala> l AbstractStringBuilder Annotation Appendable Anwendung Array AssertionStatusDirektiven BigDecimal BigInt Boolean Byte Zelle CharSequence Zeichen ZeichenDaten00 ZeichenDaten01 ZeichenDaten02 CharacterData0E CharacterDataLatin1 CharacterDataPrivateUse CharacterDataUndefined Klasse ClassLoader ClassfileAnnotation Cloneable Vergleichbarer Compiler ConditionalSpecialCasing Konsole CountedIterator Abgelehnt Double Either Enum Aufzählung Equiv Float Fractional Function GenericRange Unveränderlich InheritableThreadLocal Integer Integral Iterable Links Long Math Mutable Keine NotNull Zahl Numerisch Objekt Option Geordnete Bestellung Überschreiben Sie Package PartialFunction PartialOrdering PartiallyOrdered Predef Process ProcessBuilder ProzessUmgebung ProzessImpl Produkt Proxy Bereich RangeToString Lesbarer Antwortgeber Right Runnable Runtime RuntimePermission ScalaObject SecurityManager SerialVersionUID Kurz Herunterfahren Einige StackTraceElement StaticAnnotation StrictMath String StringBuffer StringBuilder StringCoding SuppressWarnings Symbol System SystemClassLoaderAction Terminator Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeConstraint UNIXProzess Unhashable EinzigartigkeitCache Void Schauspieler Annotation ch klonbar Kollektion com compat concurrent dbc veraltetes Inline-Instrument io java javax jline l Management mobil nativ net noinline org Paket ref reflect remote runtime scala serialisierbare Einstellungen spezialisiert sun sunw swing testing text wirft tools transient ungeprüft unversiegelt util flüchtig xml scala> l.zip zip zipAll zipWithIndex
Ziemlich klasse. Aber das ist noch nicht alles: Die trunk REPL enthält jetzt einen Poweruser-Modus:
scala> :Hilfe
Alle Befehle können abgekürzt werden - zum Beispiel :h oder :he anstelle von :help.
:help gibt diese Hilfemeldung aus.
:jar fügen Sie ein jar zum Klassenpfad hinzu.
:load gefolgt von einem Dateinamen lädt eine Scala-Datei.
:power aktivieren Sie den Poweruser-Modus.
:quit verlässt den Interpreter.
:replay setzt die Ausführung zurück und gibt alle vorherigen Befehle wieder.
:silent deaktivieren/aktivieren Sie den automatischen Druck der Ergebnisse.
scala> :power
** Power User Modus aktiviert - BEEP BOOP **
** Neue Vals! Versuchen Sie den Interpreter. **
** Neue Definitionen! Versuchen Sie mkType("T", "String") **
** Neue cmds! :Hilfe, um sie zu entdecken **
:help gibt diese Hilfemeldung aus.
:jar fügen Sie ein jar zum Klassenpfad hinzu.
:load gefolgt von einem Dateinamen lädt eine Scala-Datei.
:power aktivieren Sie den Poweruser-Modus.
:quit verlässt den Interpreter.
:replay setzt die Ausführung zurück und gibt alle vorherigen Befehle wieder.
:silent deaktivieren/aktivieren Sie den automatischen Druck der Ergebnisse.
:dump zeigt einen Überblick über den internen Zustand des Interpreters.
:tree zeigt ASTs für bestimmte Bezeichner an.
Lassen Sie uns das einmal ausprobieren. Mit mkType können wir einen Typ-Alias definieren, genau wie in Haskell:
scala> mkType("IntList", "Liste[Int]")
definierter Typ alias IntList
res3: scala.tools.nsc.InterpreterResults.Result = Erfolg
scala> val il: IntList = Liste("1", "2", "3")
:5: Fehler: Typ-Fehlanpassung;
gefunden : java.lang.String("1")
erforderlich: Int
val il: IntList = Liste("1", "2", "3")
scala> val il:IntList = Liste(1,2,3,4)
il: IntList = Liste(1, 2, 3, 4)
scala> il.foldLeft(0)(_+_)
res5: Int = 10
Funktioniert einwandfrei. Als Nächstes zeigt der Befehl :tree einige AST für Klassen und Funktionen an, die Sie definiert haben, falls Sie daran interessiert sind:
scala> def sum(a: Int)(b: Int)(c: Int) = a + b + c Summe: (a: Int)(b: Int)(c: Int)Int scala> :Baumsumme def sum(a: Int)(b: Int)(c: Int) = a.$plus(b).$plus(c) (DefDef)
Und nicht zuletzt können wir die neuen, innovativen Funktionen von Scala nutzen. So bietet Scala beispielsweise eine begrenzte Unterstützung für die Anwendung von Tail-Call-Optimierungen zur Kompilierungszeit. Die Feststellung, ob der Compiler diese Optimierung tatsächlich durchführt, kann jedoch eine knifflige Angelegenheit sein. Wenn Sie dies nutzen, aber nicht sicher sind, ob eine Funktion, die Sie geschrieben haben, tatsächlich vom Compiler optimiert wird, können Sie jetzt die @tailrec-Annotation verwenden. Zum Beispiel (das Beispiel stammt aus dem Buch Programming in Scala) ist die unten gezeigte boom-Funktion wegen der increment-Funktion am Ende nicht tail-rekursiv. Die Funktion bang hingegen schon. [scala] import scala.annotation.tailrec class Tails { @tailrec def boom(x: Int): Int = { if (x == 0) throw new Exception("boom!") else boom(x-1)+ 1 } @tailrec def bang(x: Int): Int = { if (x == 0) throw new Exception("bang!") else bang(x-1) [/scala] } } Wenn Sie die @tailrec-Annotation für beide verwenden, gibt der Compiler den folgenden Fehler aus:
:8: Fehler: konnte die mit @tailrec annotierte Methode nicht optimieren
@tailrec def boom(x: Int): Int = {
^
:13: Fehler: konnte die mit @tailrec annotierte Methode nicht optimieren
@tailrec def bang(x: Int): Int = {
Auf den ersten Blick etwas verwirrend, da wir für beide Methoden Kompilierungsfehler erhalten, während wir ziemlich sicher waren, dass die Methode bang schwanzrekursiv sein sollte. Dies lässt sich jedoch durch die Tatsache erklären, dass die Methode bang in einer Klasse als public und nicht final definiert ist. Das bedeutet, dass sie in einer Unterklasse überschrieben werden könnte, wodurch die Optimierung des Tail-Calls verhindert wird. Feinheiten wie diese machen diese Annotation wirklich sehr nützlich. Wenn wir die Klasse in ein Objekt umwandeln (für das Methoden nicht überschrieben werden können) und die @tailrec-Annotation aus der Boom-Methode entfernen, lässt sich alles problemlos kompilieren.
Verfasst von
Arjan Blokzijl
Contact



