2.2. Znaki końca wiersza
Znak średnika służy do oznaczania końca instrukcji. W niektórych sytuacjach, zależnie od kontekstu, koniec instrukcji może być też oznaczany przez znak końca wiersza. W wielu przypadkach pozwala to na ominięcie znaków średnika w kodzie programu. Jednak z drugiej strony może to prowadzić do sytuacji, kiedy Scala uznaje instrukcję za zakończoną w sytuacji, kiedy nie było to zamiarem programisty. Poniższe przykłady ilustrują różne zagadnienia związane z traktowaniem znaków nowego wiersza.
W pliku PlusMinus1.scala znajduje się definicja metody next, która zwraca wartość swojego argumentu powiększoną lub pomniejszoną o 1 w zależności od tego, czy argument jest, czy nie jest liczbą ujemną.
Plik PlusMinus1.scala: def next(a: Int) = { if (a<0) a - 1 else a + 1 }
Użyte jest w nim wyrażenie warunkowe rozpoczynające się od słowa kluczowego if, po którym w nawiasach okrągłych znajduje się wyrażenie logiczne. Jeśli wartość tego wyrażenia jest prawdziwa, to wynikiem całego wyrażenia warunkowego jest wartość wyrażenia a - 1, znajdującego się po zamykającym nawiasie okrągłym, kończącym wyrażenie logiczne. Jeśli wartość wyrażenia logicznego nie jest prawdziwa, to wynikiem całego wyrażenia warunkowego jest wartość wyrażenia a + 1, znajdującego się po słowie kluczowym else.
scala> :load PlusMinus1.scala Loading PlusMinus1.scala... next: (a: Int)Int scala> next(-2) res0: Int = -3 scala> next(2) res1: Int = 3
![]() | Wyrażenie warunkowe jest opisane w punkcie 4.1. |
W pliku PlusMinus2.scala, w definicji metody next, wprowadzony jest dodatkowy znak nowego wiersza.
Plik PlusMinus2.scala: def next(a: Int) = { if (a<0) a - 1 else a
+ 1
}
Spójrzmy jakie skutki wywołuje wprowadzona zmiana.
scala> :load PlusMinus2.scala Loading PlusMinus2.scala... next: (a: Int)Int scala> next(-2) res2: Int = 1 scala> next(2) res3: Int = 1
Kompilator uznał zawartość wierszy
i
za poprawne składniowo, ale
oddzielne wyrażenia, a nie za jedno wyrażenie warunkowe, zapisane w
dwóch oddzielnych wierszach. Ponieważ wyrażenie + 1 jest ostatnim
wyrażeniem w bloku kodu definiującym treść metody, jego wartość staje
się wynikiem wywołania metody.
W definicji metody next z pliku PlusMinus3.scala, znak nowego wiersza znajduje się przed słowem kluczowym else.
Plik PlusMinus3.scala: def next(a: Int) = { if (a<0) a - 1 else a + 1 }
Tym razem wyniki wywołania metody są takie, jak w przypadku metody next z pliku PlusMinus1.scala.
scala> :load PlusMinus3.scala Loading PlusMinus3.scala... next: (a: Int)Int scala> next(-2) res4: Int = -3 scala> next(2) res5: Int = 3
Wiersz, który zaczyna się od słowa kluczowego else, nie może zostać uznany za poprawnie rozpoczynającą się instrukcję języka Scala. Wobec tego kompilator uznaje ten wiersz za ciąg dalszy wyrażenia warunkowego z poprzedniego wiersza.
W pliku PlusMinus4.scala znak nowego wiersza jest umieszczony po znaku +.
Plik PlusMinus4.scala: def next(a: Int) = { if (a<0) a - 1 else a + 1 }
Wyniki znowu odpowiadają rezultatom wywołania metody z pliku PlusMinus1.scala.
scala> :load PlusMinus4.scala Loading PlusMinus4.scala... next: (a: Int)Int scala> next(-2) res6: Int = -3 scala> next(2) res7: Int = 3
Pozostawienie znaku + na końcu wiersza powoduje, że kompilator nie uznaje wyrażenia za prawidłowo zakończone. Początek kolejnego wiersza uznany zostaje zatem za kontynuację wyrażenia.
W pliku PlusMinus5.scala wyrażenie a + 1 jest ujęte w nawiasy okrągłe.
Plik PlusMinus5.scala: def next(a: Int) = { if (a<0) a - 1 else (a + 1) }
Wyniki ponownie są takie, jak wcześniej.
scala> :load PlusMinus5.scala Loading PlusMinus5.scala... next: (a: Int)Int scala> next(-2) res8: Int = -3 scala> next(2) res9: Int = 3
Wyrażenie a + 1, mimo że rozbite na dwa wiersze, jest traktowane jako jedno, gdyż znajduje się w nawiasach okrągłych. Znak nowego wiersza wewnątrz wyrażenia w nawiasach okrągłych nie jest traktowany jako separator instrukcji.
W pliku PlusMinus6.scala zamiast nawiasów okrągłych użyte zostały nawiasy klamrowe.
Plik PlusMinus6.scala: def next(a: Int) = { if (a<0) a - 1 else {a + 1} }
Tym razem wyniki wywołania metody różnią się od wcześniejszych, a przy okazji kompilator pokazuje ostrzeżenie.
scala> :load PlusMinus6.scala
Loading PlusMinus6.scala...
<console>:11: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
if (a<0) a - 1 else {a
^
next: (a: Int)Int
scala> next(-2)
res10: Int = -3
scala> next(2)
res11: Int = 1
Po słowie kluczowym else znajduje się blok kodu zawierający w nawiasach klamrowych dwa wyrażenia. Wyrażenia a oraz + 1 są traktowane jako dwa oddzielne, prawidłowo zbudowane wyrażenia języka Scala. Wobec tego, że wyrażenie + 1 jest ostatnim wyrażeniem bloku kodu z klauzuli else, jego wynik jest zwracany jako wynik całej metody, w przypadku gdy argumentem metody jest liczba nieujemna. Wartość pierwszego wyrażenia z bloku kodu (czyli wyrażenia a) jest w tym przypadku ignorowana (i tego zasadniczo dotyczy ostrzeżenie kompilatora).
Powyższe przykłady zawierają sytuacje, kiedy kompilator nie generuje komunikatu o błędzie, mimo że intencje programisty są być może interpretowane opacznie. Od popełnienia podobnych błędów mogą nas ustrzec odpowiednia czujność lub testy.
Choć w wielu sytuacjach możemy opuścić znaki średnika, to jeśli chcemy umieścić kilka instrukcji w tym samym wierszu, należy je tymi znakami oddzielić, jak w poniższym przykładzie.
scala> val a = 1; val b = 2; val c = 3 a: Int = 1 b: Int = 2 c: Int = 3
![]() | Specyfikacja języka Scala opisuje reguły dotyczące interpretacji znaków końca wiersza w punkcie 1.2. |
Plik PlusMinus1.scala:
def next(a: Int) = {
if (a<0) a - 1 else a + 1
}

