17 Stimmen

Warum schlägt die Semikolon-Inferenz von Scala hier fehl?

Beim Kompilieren des folgenden Codes mit Scala 2.7.3,

package spoj

object Prime1 {
  def main(args: Array[String]) {
    def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0))
    val read = new java.util.Scanner(System.in)
    var nTests = read nextInt // [*]
    while(nTests > 0) {
      val (start, end) = (read nextInt, read nextInt)
      start to end filter(isPrime(_)) foreach println
      println
      nTests -= 1
    }
  }
}

Ich erhalte den folgenden Kompilierzeitfehler:

PRIME1.scala:8: error: illegal start of simple expression
    while(nTests > 0) {
    ^
PRIME1.scala:14: error: block must end in result expression, not in definition
  }
  ^
two errors found

Wenn ich am Ende der kommentierten Zeile ein Semikolon hinzufüge, wie [*] kompiliert das Programm problemlos. Kann jemand bitte erklären, warum Scala Semikolon Inferenz nicht auf diese bestimmte Zeile zu arbeiten?

19voto

oxbow_lakes Punkte 131223

Ist es, weil Scala davon ausgeht, dass Sie die Syntax verwenden a foo b (gleichbedeutend mit a.foo(b) ) in Ihrem Aufruf an readInt . Das heißt, sie geht davon aus, dass die while Schleife ist das Argument für readInt (es sei daran erinnert, dass jeder Ausdruck einen Typ hat) und daher ist die letzte Anweisung eine Deklaration:

var ntests = read nextInt x

wobei x ist Ihr while-Block.

Ich muss sagen, dass ich jetzt wieder das übliche Verfahren verwende, um die a.foo(b) Syntax über a foo b es sei denn, Sie arbeiten mit einer DSL, die speziell für diesen Zweck entwickelt wurde (wie Schauspieler a ! b ). Dadurch werden die Dinge im Allgemeinen viel klarer, und man wird nicht von solchen seltsamen Dingen gebissen!

11voto

ColinHowe Punkte 473

Zusätzlicher Kommentar zur Antwort von oxbow_lakes...

var ntests = read nextInt()

Sollte als Alternative zum Semikolon die Dinge für Sie regeln

8voto

Matt R Punkte 8879

Um ein wenig mehr über die Semikolon-Inferenz hinzuzufügen, Scala tut dies tatsächlich in zwei Stufen. Zuerst wird ein spezielles Token gefolgert, das nl durch die Sprachspezifikation. Der Parser erlaubt nl als Anweisungstrennzeichen zu verwenden, ebenso wie Semikolons. Allerdings, nl ist auch an ein paar anderen Stellen durch die Grammatik erlaubt. Insbesondere kann eine einzelne nl ist nach Infix-Operatoren erlaubt, wenn das erste Token in der nächsten Zeile einen Ausdruck beginnen kann -- und while kann einen Ausdruck einleiten und wird deshalb auch so interpretiert. Leider, obwohl while einen Ausdruck beginnen kann, kann eine while-Anweisung nicht in einem Infix-Ausdruck verwendet werden, daher der Fehler. Ich persönlich finde die Funktionsweise des Parsers etwas eigenartig, aber soweit ich weiß, steckt dahinter eine vernünftige Logik!

Eine weitere Option zu den anderen Vorschlägen ist das Einfügen eines leeren Zeilenumbruchs zwischen Ihren [*] Linie und die while Zeile behebt das Problem ebenfalls, da nur eine einzige nl ist nach Infix-Operatoren erlaubt, so dass mehrere nl s erzwingt eine andere Interpretation durch den Parser.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X