17.7. Wyrażenie return w anonimowych funkcjach
Anonimowe funkcje są w rzeczywistości pewnymi obiektami zawierającymi metodę apply. Jeśli taka anonimowa funkcja zawiera wyrażenie return, to wyrażenie to powoduje zakończenie nie tylko działania samej anonimowej funkcji (a więc metody apply zawierającej jej kod), ale również metody, w której ta funkcja była zdefiniowana. Metoda hello, zdefiniowana w pliku Return4.scala, definiuje i wywołuje funkcję anonimową przypisaną do wartości greet. Ta funkcja anonimowa zawiera wyrażenie return.
Plik Return4.scala: def hello(n: Int): String = { val greet = (greeting: String, n: Int) => { if (n <= 0) return "wrong parameter value: "+n (greeting+" ") * n } val result = greet("Hello!",n) println("returning: "+result) result }
Metoda hello pobiera argument w postaci liczby całkowitej i jeśli podana wartość jest dodatnia, to zwraca łańcuch znaków zawierający pozdrowienie powtórzone odpowiednią liczbę razy. Ponieważ metoda zawiera wywołanie metody println, to przed przekazaniem rezultatu, na ekranie zostaje wyświetlona odpowiednia informacja.
scala> :load Return4.scala Loading Return4.scala... hello: (n: Int)String scala> hello(4) returning: Hello! Hello! Hello! Hello! res0: String = "Hello! Hello! Hello! Hello! "
Jeśli jednak metodzie hello zostanie podany argument w postaci liczby zero lub liczby ujemnej, to zwrócony łańcuch znaków będzie zawierał informację o błędnych danych wejściowych. Ponieważ informacja o błędzie jest zwracana z funkcji anonimowej przy pomocy wyrażenia return, to w takim przypadku nie zostanie wywołana metoda println z wiersza . Zamiast tego, wyrażenie return powoduje natychmiastowe zakończenie działania metody hello.
scala> hello(0) res1: String = wrong parameter value: 0
Implementacja wyrażenia return — takiego jak w wierszu — wykorzystuje mechanizm wyjątków. Wyjście z metody hello jest zaimplementowane przy użyciu wyjątku będącego instancją klasy scala.runtime.NonLocalReturnControl. W pliku Return5.scala znajduje się zmodyfikowana wersja metody hello, w której dodane zostało wyrażenie try z klauzulą catch (wiersz i kolejne). W tej klauzuli następuje przechwycenie tego wyjątku, wypisanie informacji na ekranie i ponowne wyrzucenie wyjątku. Dzięki temu można przekonać się, że rzeczywiście implementacja metody korzysta z takiego wyjątku.
Plik Return5.scala: def hello(n: Int): String = { val greet = (greeting: String, n: Int) => { if (n <= 0) return "wrong parameter value: "+n (greeting+" ") * n } val result = try greet("Hello!",n) catch { case ex: scala.runtime.NonLocalReturnControl[_] => println("ex: "+ex); throw ex } println("returning: "+result) result }
Poniższy przykład ilustruje fakt wykorzystania wyjątku NonLocalReturnControl.
scala> :load Return5.scala Loading Return5.scala... hello: (n: Int)String scala> hello(0) ex: scala.runtime.NonLocalReturnControl res2: String = wrong parameter value: 0