7.8. Parametry przekazywane przez nazwę
Parametry metod w Scali mogą być przekazywane przez wartość lub przez nazwę. Dotychczas używane w tym rozdziale parametry były przekazywane przez wartość. W przypadku takiego parametru wartość argumentu w wywołaniu metody jest obliczana przed wywołaniem samej metody.
Parametr metody greet1, zdefiniowanej w pliku ByNameParameters1.scala, jest przekazywany przez wartość. Wobec tego jego ewaluacja następuje przed wywołaniem samej metody.
Plik ByNameParameters1.scala: def greet1(greeting: String) { println("in greet") println(greeting + "!") }
W pliku ByNameParameters2.scala zdefiniowana jest metoda hello, która zwraca łańcuch znaków, wcześniej wyświetlając komunikat na ekranie. Ta metoda posłuży do zilustrowania użycia parametrów przekazywanych przez wartość i przez nazwę.
Plik ByNameParameters2.scala: def hello:String = { println("in hello") "hello" }
W poniższym przykładzie najpierw wykonana zostaje metoda hello obliczająca argument metody greet1, a dopiero potem wywołana zostaje metoda greet1.
scala> :load ByNameParameters1.scala Loading ByNameParameters1.scala... greet1: (greeting: String)Unit scala> :load ByNameParameters2.scala Loading ByNameParameters2.scala... hello: String scala> greet1(hello) in hello in greet hello!
Jeśli chcemy, aby wartość parametru była przekazywana przez nazwę, to między znakiem dwukropka, a specyfikacją typu parametru należy umieścić podwójną strzałkę w prawo (czyli znaki => lub znak ⇒). Parametry przekazywane przez nazwę są ewaluowane dopiero w momencie odwołania się do nich wewnątrz metody. Metoda greet3, zdefiniowana w pliku ByNameParameters3.scala, zawiera deklarację parametru przekazywanego przez nazwę.
Plik ByNameParameters3.scala: def greet3(greeting: => String) { println("in greet") println(greeting + "!") }
W poniższym przykładzie wywołanie metody hello następuje dopiero po wywołaniu metody greet3, w momencie, w którym w tej metodzie następuje odwołanie do przekazanego przez nazwę parametru greeting.
scala> :load ByNameParameters3.scala Loading ByNameParameters3.scala... greet3: (greeting: => String)Unit scala> greet3(hello) in greet in hello hello!
Ewaluacja argumentu przekazanego przez nazwę następuje przy każdym odwołaniu do parametru w ciele metody. W zdefiniowanej w pliku ByNameParameters4.scala metodzie o nazwie greet4 odwołanie do parametru greeting występuje dwukrotnie.
Plik ByNameParameters4.scala: def greet4(greeting: => String) { println("in greet"); println(greeting + "!") println(greeting + "!!") }
Wykonanie poniższego wyrażenia skutkuje dwukrotnym wywołaniem metody hello.
scala> :load ByNameParameters4.scala Loading ByNameParameters4.scala... greet4: (greeting: => String)Unit scala> greet4(hello) in greet in hello hello! in hello hello!!
Ewaluacja argumentu przekazanego przez nazwę może w ogóle nie nastąpić. Skoro ewaluacja argumentu przekazanego przez nazwę występuje przy każdym odwołaniu do parametru w ciele metody, to jeśli takie odwołanie nie nastąpi, argument nie będzie w ogóle obliczony. Metoda zdefiniowana w pliku ByNameParameters5.scala, w zależności od wartości logicznej przekazanej w pierwszym parametrze, wykonuje kod przekazany albo w drugim, albo w trzecim parametrze.
Plik ByNameParameters5.scala: def ifelse(cond: Boolean, ifblock: => Unit, elseblock: => Unit) = if (cond) ifblock else elseblock
Przykładowe wywołania tej metody pokazują, że metoda wywołuje jeden z dwóch przekazanych jej bloków kodu, a drugi pozostaje niewywołany.
scala> :load ByNameParameters5.scala Loading ByNameParameters5.scala... ifelse: (cond: Boolean, ifblock: => Unit, elseblock: => Unit)Unit scala> var sayHello = true sayHello: Boolean = true scala> ifelse(sayHello, println("Hello"), println("Hi")) Hello scala> sayHello = false sayHello: Boolean = false scala> ifelse(sayHello, println("Hello"), println("Hi")) Hi
Specyfikacja języka Scala opisuje parametry przekazywane przez nazwę w punkcie 4.6.2. |