2010-09-15 10 views
17

Ich denke Scala geht zu weit von der Einfachheit, wie seine Syntax. Zum Beispiel Martin Odersky die Methode in seinem Buch schrieb:Scala Codierungsstile und Konventionen?

def calculate(s: String): Int = 
    if (cache.contains(s)) 
    cache(s) 
    else { 
    val acc = new ChecksumAccumulator 
    for (c <- s) 
     acc.add(c.toByte) 
    val cs = acc.checksum() 
    cache += (s -> cs) 
    cs 
    } 

Wenn die Methoden wächst, wird es sehr schmerzhaft, den Code zu lesen, kann ich nicht geschweiften Klammern übereinstimmen, kann die Methode nicht in IDE falten. Gibt es irgendwelche Scala-Kodierungskonventionen? Ich glaube, es ist zu flexibel, ein einfaches Verfahren zum Ausdruck bringen:

def add(b: Byte): Unit = { 
    sum += b 
} 

def add(b: Byte): Unit = sum += b 

def add(b: Byte) { sum += b } 
+0

Was würden diese Codierung Konventionen zu tun versuchen? – wheaties

+7

Da es zu viele Möglichkeiten gibt, eine einfache Codezeile in Scala auszudrücken, würden Codierungskonventionen dazu beitragen, Codes in Teams oder Communities zu formalisieren. – Sawyer

+0

Wie würde eine Konvention in Ihrem zweiten Codebeispiel zu Ihrem ersten Beispiel für Lesbarkeit beitragen? – Debilski

Antwort

35

„Wenn die Methode wächst es sehr schmerzhaft wird, den Code zu lesen“. Ich denke, ein Teil der Antwort ist, dass Methoden nicht wachsen sollten. Der funktionale Programmierstil besteht darin, viele kleine Methoden zu verwenden. Die Methode calculate ist bereits auf der großen Seite.

Um die allgemeineren Fragen zu Styleguides für Scala-Programmierung zu beantworten: Hier ist ein representative example.

+0

Dies ist besonders einfach, weil Sie Methoden innerhalb von Methoden definieren können! Eine gute Möglichkeit, den Code zu brechen. Und viel schöner als private Begleitmethoden für rekursive Funktionen wie in Java. – schmmd

4

Das spezielle Beispiel, die Sie zitieren können komplex aussehen, weil es einen Cache verwendet, die Ergebnisse memoize. Wenn Sie die Memoisierung entfernen, reduzieren Sie die Methode auf:

was ich denke, ist überhaupt nicht komplex.

+0

Ihre Tabs sind durcheinander. – Det

24

Hier ist ein Link zum Scala Style Guide.


Der geschweiften Klammern Abschnitt sagt:

Curly-Streben:

Curly-Klammern sollten in Fällen verzichtet werden, wenn die Struktursteuerung einen rein- funktionellen darstellt Betrieb und alle Zweige der Kontrollstruktur (relevant für if/else) sind einzeilige Ausdrücke. Beachten Sie die folgenden Richtlinien:

  • wenn - Auslassen klammern, wenn Sie eine andere Klausel haben. Andernfalls umgeben Sie die Inhalte mit geschweiften Klammern, auch wenn die Inhalte nur eine einzige Zeile sind.

  • while - Stützen Sie nie weg (während kann nicht in einer reinen Funktion Weise verwendet werden).

  • for - Auslassen Klammern, wenn Sie eine Yield-Klausel haben. Sonst umgibt der Inhalt mit geschweiften Klammern, auch wenn der Inhalt nur eine einzige Zeile ist.

  • Fall - Klammern auslassen, wenn der Fall Ausdruck ts auf einer einzigen Zeile ist. Ansonsten verwenden Sie geschweifte Klammern für Klarheit (obwohl sie nicht vom Parser benötigt sind).

    val news = if (foo) 
        goodNews() 
    else 
        badNews() 
    
    if (foo) { 
        println("foo was true") 
    } 
    
    news match { 
        case "good" => println("Good news!") 
        case "bad" => println("Bad news!") 
    } 
    

Ich wünschte, die Leute diesen Style Guide gefolgt :(


Bitte beachten Sie, dass ich bin nicht einverstanden mit "auslassen klammern, wenn if eine else Klausel" -Teil.Ich würde viel lieber den Code so sehen:

def calculate(s: String): Int = { 
    if (cache.contains(s)) { 
    cache(s) 
    } else { 
    val acc = new ChecksumAccumulator 
    for (c <- s) { 
     acc.add(c.toByte) 
    } 
    val cs = acc.checksum() 
    cache += (s -> cs) 
    cs 
    } 
} 
+1

Klammern hilft, die Codes zu formatieren, ich mag auch Ihre Stile, vielleicht komme ich nur aus Java. – Sawyer

+0

Ich weiß nicht, warum eine Konvention jemals überflüssige Interpunktion fordern würde. –

+0

@Randall: In Java Welt tut es, und das aus einem guten Grund: es macht Code leichter zu refactor, und lesen (meiner Meinung nach). – missingfaktor

1

Hier ist das Wort von dem Mann, der scala schrieb, selbst, und immer noch der Hauptimplementierer dieser Sprache.

Quelle: Functional Programming Principles in Scala von Martin Odersky

Sie auch eingeladen werden nun seinen Lauf zu nehmen oder das nächste Angebot link [1]

========== =================

Scala Style Guide Hilfe

auf dieser Seite finden Sie eine Liste der häufigsten Fragen, die wir während bei einigen Ausführungen der Suche erkannt.

Einige der Stileigenschaften können von der automatischen Formatprüfung erkannt werden, die wir auch für den Sortierprozess verwenden. Der Style-Checker, der auf Scalastyle basiert, kann lokal in sbt ausgeführt werden, indem die styleCheck-Task ausgeführt wird.

Häufige Probleme

1 Vermeiden Sie Casts und Typprüfungen

Nie isInstanceOf oder asInstanceOf verwenden - es gibt immer eine bessere Lösung, sowohl für die Aufgaben, und auch für jede der realen Welt Scala-Projekt. Wenn Sie feststellen, dass Sie Gussformen verwenden möchten, machen Sie einen Schritt zurück und überlegen Sie, was Sie erreichen möchten. Lesen Sie die Zuweisungsanweisungen erneut und schauen Sie sich die entsprechenden Vortragsvideos noch einmal an.

2 Einrückungen

Code Stellen Sie sicher, richtig gegliederte ist, wird es viel besser lesbar.

Das mag für unsere Übungen trivial und nicht sehr relevant erscheinen, aber stellen Sie sich vor, Sie sind Teil eines Teams, arbeiten an den gleichen Dateien mit anderen Programmierern: Es ist sehr wichtig, dass alle die Regeln respektieren Code gesund.

Wenn Ihr Editor die Einrückung nicht so durchführt, wie Sie es möchten, sollten Sie herausfinden, wie Sie die Einstellungen ändern können. In Scala besteht der Standard darin, mit 2 Leerzeichen einzurücken (keine Tabs).

3 Zeilenlänge und Leer

Achten Sie darauf, die Linien sind nicht zu lange, sonst wird Ihr Code ist sehr schwer zu lesen. Anstatt sehr lange Zeilen zu schreiben, führen Sie einige lokale Wertbindungen ein. Die Verwendung von Leerzeichen macht Ihren Code einheitlich lesbarer.

Beispiel (lange Linie, fehlende Leerzeichen):

if(p(this.head))this.tail.filter0(p, accu.incl(this.head))else this.tail.filter0(p, accu) 

Besser:

if (p(this.head)) 
    this.tail.filter0(p, accu.incl(this.head)) 
else 
    this.tail.filter0(p, accu) 

Noch besser (# 4 und # 6 siehe unten):

val newAccu =

if (p(this.head)) accu.incl(this.head) 
    else accu 
this.tail.filter0(p, newAccu) 

4 Verwenden Sie lokal Werte zur Vereinfachung komplexer Ausdrücke

Wenn Code in funktionalem Stil geschrieben wird, werden Methoden häufig als eine Kombination von Funktionsaufrufen implementiert. Wenn ein solcher kombinierter Ausdruck zu groß wird, wird der Code möglicherweise schwer zu verstehen sein.

In solchen Fällen ist es besser, einige Argumente in einem lokalen Wert zu speichern, bevor sie an die Funktion übergeben werden (siehe # 3 oben). Stellen Sie sicher, dass der lokale Wert einen aussagekräftigen Namen hat (siehe unten # 5)!

5 Wählen Sie aussagekräftige Namen für Methoden und Werte

Die Namen der Methoden, Felder und Werte sollten sorgfältig so gewählt werden, dass der Quellcode ist leicht zu verstehen. Ein Methodenname sollte klarstellen, was die Methode macht. Nein, Temp ist nie ein guter Name :-)

Einige verbesserungs Beispiele:

val temp = sortFuntion0(list.head, tweet) // what does sortFunction0 do? 
def temp(first: TweetSet, second : TweetSet): TweetSet = ... 
def un(th: TweetSet,acc: TweetSet): TweetSet = ... 
val c = if (p(elem)) accu.incl(elem) else accu 
def loop(accu: Trending, current: TweetSet): Trending = ... 
def help(ch: Char, L2: List[Char], compteur: Int): (Char, Int) = ... 
def help2(L: List[(Char, Int)], L2: List[Char]): List[(Char, Int)] = ... 

6 Häufige Teilausdrücke

Sie sollten unnötige Anrufungen von rechenintensiven Methoden vermeiden. Zum Beispiel

this.remove(this.findMin).ascending(t + this.findMin) 

ruft die this.findMin-Methode zweimal auf. Wenn jeder Aufruf teuer ist (zB hat eine gesamte Datenstruktur zu durchlaufen) und hat keine Nebenwirkungen und Sie können sparen, indem Sie einen lokalen Wert Einführung Bindung:

val min = this.findMin 
this.remove(min).ascending(t + min) 

Dies, wenn die Funktion noch wichtiger wird wird rekursiv aufgerufen: In diesem Fall wird die Methode nicht nur mehrmals, sondern exponentiell aufgerufen.

7 Kopieren Sie den Code nicht!

Kopieren-Einfügen-Code ist immer ein Warnzeichen für schlechten Stil! Es gibt viele Nachteile:

Der Code ist länger, es mehr Zeit in Anspruch nimmt es zu verstehen, wenn die beiden Teile nicht identisch sind, aber sehr ähnlich ist, ist es sehr schwierig, die Unterschiede zu erkennen (siehe Beispiel unten) zwei pflegen Kopieren und sicherstellen, dass sie synchronisiert bleiben, ist sehr fehleranfällig Die Menge der Arbeit, die erforderlich ist, um Änderungen am Code vorzunehmen, wird multipliziert Sie sollten gemeinsame Teile in separaten Methoden ausschließen, anstatt Code herum zu kopieren.Beispiel (siehe auch 3 # oben für ein anderes Beispiel):

val googleTweets: TweetSet = TweetReader.allTweets.filter(tweet => 
    google.exists(word => tweet.text.contains(word))) 
val appleTweets: TweetSet = TweetReader.allTweets.filter(tweet => 
    apple.exists(word => tweet.text.contains(word))) 
This code is better written as follows: 

def tweetsMentioning(dictionary: List[String]): TweetSet = 
    TweetReader.allTweets.filter(tweet => 
    dictionary.exists(word => tweet.text.contains(word))) 

val googleTweets = tweetsMentioning(google) 
val appleTweets = tweetsMentioning(apple) 

8 Scala erfordert keine Semikolons

Semikolons in Scala sind nur erforderlich, wenn mehrere Anweisungen auf der gleichen Zeile zu schreiben. Schreiben unnötige Semikolons sollte vermieden werden, zum Beispiel:

def filter(p: Tweet => Boolean): TweetSet = filter0(p, new Empty); 

9 Sie einreichen-Code nicht mit „print“ Statements

Sie sollten Ihren Code aufzuräumen und entfernen Sie alle Druck oder println Aussagen vor dem Absenden. Das gleiche gilt, wenn Sie für ein Unternehmen arbeiten und Code erstellen, der in der Produktion verwendet wird: Der endgültige Code sollte keine Debugging-Anweisungen enthalten.

10 Vermeiden Return mit

In Scala, Sie oft brauchen keine explizite Rückkehr zu verwenden, da Kontrollstrukturen wie wenn Ausdrücke sind. Zum Beispiel in

def factorial(n: Int): Int = { 
    if (n <= 0) return 1 
    else return (n * factorial(n-1)) 
} 

die Return-Anweisungen können einfach fallen gelassen werden.

11 Vermeiden wandelbar lokale Variablen

Da dies ein Kurs über funktionale Programmierung ist, möchten wir Ihnen das Schreiben von Code in einem rein funktionalen Stil gewöhnen, ohne Neben bewirken Operationen. Sie können Code häufig überschreiben, der veränderbare lokale Variablen verwendet, um mit Hilfsfunktionen zu codieren, die Akkumulatoren aufnehmen. Statt:

def fib(n: Int): Int = { 
    var a = 0 
    var b = 1 
    var i = 0 
    while (i < n) { 
    val prev_a = a 
    a = b 
    b = prev_a + b 
    i = i + 1 
    } 
    a 
} 

bevorzugen:

def fib(n: Int): Int = { 
    def fibIter(i: Int, a: Int, b: Int): Int = 
    if (i == n) a else fibIter(i+1, b, a+b) 
    fibIter(0, 0, 1) 
} 

12 überflüssig beseitigen „Wenn“ Ausdrücke

statt

if (cond) true else false 

Sie einfach schreiben können

cond 

(Ähnlich für den negaitve Fall).

Andere Styling-Probleme? Bitte poste das Forum mit den Style oder StyleChecktags und wir werden diesen Style Guide mit Vorschlägen ergänzen.

+2

Punkt # 5 ist lustig, wenn man bedenkt, dass das scaladoc nur voll von Argumentnamen namens 'k',' g', 'p' und' z' ist. – jbx

+0

Ich habe nicht bemerkt, als ich schrieb, dass der Hersteller der Sprache selbst hier gepostet hat. Vielleicht möchten Sie seine Beiträge über Scala zu den syntaktischen Konventionen lesen. http://StackOverflow.com/a/3718851/1984636 – sivi