11.2. Funkcje anonimowe
Definiując funkcje nie trzeba uciekać się do bezpośredniego rozszerzania jednej z klas o nazwie FunctionN i implementowania jej metody apply. Scala udostępnia specjalną notację pozwalającą definiować funkcje. Poniżej pokazano alternatywne sposoby zdefiniowania funkcji hello i isGreater z poprzedniego podrozdziału, przy czym są to definicje funkcji anonimowych, co oznacza, że tym funkcjom nie są nadawane nazwy.
- () => "Hello!"
- (a: Int, b:Int) ⇒ a > b
Każda z powyższych definicji funkcji anonimowej składa się z deklaracji listy parametrów w nawiasach okrągłych, po której następuje podwójna strzałka w prawo (znaki => lub znak ⇒), a po niej treść ciała funkcji. Choć tak zdefiniowana funkcja nie ma nazwy, to możemy ją przypisać do wartości zdefiniowanej za pomocą słowa kluczowego val i dalej odwoływać się do niej za pomocą nazwy tej wartości.
scala> val hello = () => "Hello!" hello: () => String = <function0> scala> val isGreater = (a: Int, b:Int) => a > b isGreater: (Int, Int) => Boolean = <function2>
Tak zdefiniowane funkcje wywołujemy jak poprzednio.
scala> hello() res0: String = Hello! scala> isGreater(2,1) res1: Boolean = true
Możemy również jawnie wywołać metodę apply.
scala> hello.apply() res2: String = Hello! scala> isGreater.apply(2,1) res3: Boolean = true
Jeśli typ funkcji anonimowej jest znany — na przykład dzięki temu, że jawnie zadeklarujemy typ wartości do której przypisujemy funkcję — w definicji funkcji możemy zrezygnować z jawnego podawania typu parametrów.
scala> val isGreater: (Int, Int) => Boolean = (a,b) => a > b isGreater: (Int, Int) => Boolean = <function2>
Możemy również zrobić to selektywnie.
scala> val isGreater: (Int, Int) => Boolean = (a:Int,b) => a > b isGreater: (Int, Int) => Boolean = <function2> scala> val isGreater: (Int, Int) => Boolean = (a,b:Int) => a > b isGreater: (Int, Int) => Boolean = <function2>
W przypadku funkcji jednoparametrowej z pominiętą deklaracją typu możemy również pominąć nawiasy otaczające listę parametrów funkcji. Z taką sytuacją mamy do czynienia w następującej definicji.
scala> val isGreaterThan5: (Int) => Boolean = x => x > 5 isGreaterThan5: Int => Boolean = <function1>
Zapis definicji funkcji isGreater może być jeszcze krótszy. Zauważmy, że każdy z parametrów funkcji jest jest użyty w ciele funkcji tylko raz, a ponadto parametry są użyte w tej samej kolejności, w której występują na liście parametrów. W takiej sytuacji możemy pominąć deklaracje parametrów oraz podwójną strzałkę, a w ciele funkcji zastąpić odwołania do parametrów znakami podkreślenia. Definicja funkcji isGreater skraca się w ten sposób do następującej postaci.
scala> val isGreater: (Int, Int) => Boolean = _ > _ isGreater: (Int, Int) => Boolean = <function2>
Ponieważ definicja funkcji nie zawiera informacji o typach parametrów, próba zastosowania go z jednoczesnym pominięciem jawnej deklaracji typu funkcji — jak poniżej — kończy się komunikatem o błędzie.
scala> val isGreater = _ > _ <console>:10: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$greater(x$2)) val isGreater = _ > _ ^ <console>:10: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$greater(x$2)) val isGreater = _ > _ ^
Można jednak uzupełnić znaki podkreślenia oznaczające parametry funkcji deklaracjami typu.
scala> val isGreater = (_: Int) > (_: Int) isGreater: (Int, Int) => Boolean = <function2>
Specyfikacja języka Scala opisuje funkcje anonimowe w punkcie 6.23. Scala umożliwia zastosowanie jeszcze innej specjalnej składni, która może być zastosowana do tworzenia funkcji anonimowych. Ta składnia zostanie przedstawiona w punkcie 14.15. |