感謝 Scala 的一致性,撰寫回傳函式的函式與您在先前各節中所見的內容類似。例如,想像一下您想要撰寫回傳函式的 greet
函式。我們再次從問題陳述開始
我想建立回傳函式的
greet
函式。該函式將接收字串參數,並使用println
進行列印。為了簡化這個第一個範例,greet
函式不會接收任何輸入參數;它只會建立一個函式並回傳它。
根據該陳述,您可以開始建立 greet
函式。您知道它會是一個函式
def greet()
您也知道這個方法會回傳一個函式,這個函式 (a) 接收一個 String
參數,以及 (b) 使用 println
函式列印該字串。因此,該函式的類型為 String => Unit
def greet(): String => Unit = ???
----------------
現在您只需要一個方法主體。您知道該方法需要回傳一個函式,而該函式會接收一個 String
並列印它。這個匿名函式符合該描述
(name: String) => println(s"Hello, $name")
現在您只要從該方法回傳該函式即可
// a method that returns a function
def greet(): String => Unit =
(name: String) => println(s"Hello, $name")
由於這個方法會回傳一個函式,因此您可以透過呼叫 greet()
來取得該函式。這是可以在 REPL 中執行的良好步驟,因為它會驗證新函式的類型
scala> val greetFunction = greet()
val greetFunction: String => Unit = Lambda....
-----------------------------
現在您可以呼叫 greetFunction
greetFunction("Joe") // prints "Hello, Joe"
恭喜您,您剛剛建立了一個會回傳函式的函式,然後執行該函式。
改善方法
如果您能傳入一個問候語,我們的函式會更有用,因此我們來這麼做。您只需要將問候語作為參數傳遞給 greet
方法,並在 println
內部的字串中使用它
def greet(theGreeting: String): String => Unit =
(name: String) => println(s"$theGreeting, $name")
現在當您呼叫您的方法時,這個程序會更靈活,因為您可以變更問候語。當您從這個方法建立一個函式時,它看起來會像這樣
scala> val sayHello = greet("Hello")
val sayHello: String => Unit = Lambda.....
------------------------
REPL 類型簽章輸出顯示 sayHello
是接收 String
輸入參數並回傳 Unit
(無) 的函式。因此,現在當您給予 sayHello
一個 String
時,它會列印問候語
sayHello("Joe") // prints "Hello, Joe"
您也可以變更問候語來建立新的函式,視需要而定
val sayCiao = greet("Ciao")
val sayHola = greet("Hola")
sayCiao("Isabella") // prints "Ciao, Isabella"
sayHola("Carlos") // prints "Hola, Carlos"
更貼近真實世界的範例
當您的方法回傳許多可能的函式之一時,這個技術會更有用,例如回傳自訂函式的工廠。
例如,假設您想要撰寫一個方法,這個方法會回傳使用不同語言向人們問候的函式。我們會將此限制為使用英文或法文問候的函式,這取決於傳遞給該方法的參數。
您首先知道您想要建立一個方法,這個方法 (a) 接收「目標語言」作為輸入,以及 (b) 回傳一個函式作為其結果。此外,由於該函式會列印給予它的字串,因此您知道它的類型為 String => Unit
。有了這些資訊,您可以撰寫方法簽章
def createGreetingFunction(desiredLanguage: String): String => Unit = ???
接下來,由於您知道您會回傳的可能函式會接收一個字串並列印它,因此您可以為英文和法文撰寫兩個匿名函式
(name: String) => println(s"Hello, $name")
(name: String) => println(s"Bonjour, $name")
在方法內部,如果您給這些匿名函式一些名稱,可能會更易於閱讀,因此我們將它們指定給兩個變數
val englishGreeting = (name: String) => println(s"Hello, $name")
val frenchGreeting = (name: String) => println(s"Bonjour, $name")
現在您所需要做的就是 (a) 如果 desiredLanguage
是英文,則傳回 englishGreeting
,以及 (b) 如果 desiredLanguage
是法文,則傳回 frenchGreeting
。一種做法是使用 match
表達式
def createGreetingFunction(desiredLanguage: String): String => Unit = {
val englishGreeting = (name: String) => println(s"Hello, $name")
val frenchGreeting = (name: String) => println(s"Bonjour, $name")
desiredLanguage match {
case "english" => englishGreeting
case "french" => frenchGreeting
}
}
def createGreetingFunction(desiredLanguage: String): String => Unit =
val englishGreeting = (name: String) => println(s"Hello, $name")
val frenchGreeting = (name: String) => println(s"Bonjour, $name")
desiredLanguage match
case "english" => englishGreeting
case "french" => frenchGreeting
這就是最後的方法。請注意,從方法傳回函式值與傳回字串或整數值並無不同。
這是 createGreetingFunction
建立法文問候函式的方式
val greetInFrench = createGreetingFunction("french")
greetInFrench("Jonathan") // prints "Bonjour, Jonathan"
這是它建立英文問候函式的方式
val greetInEnglish = createGreetingFunction("english")
greetInEnglish("Joe") // prints "Hello, Joe"
如果您對該程式碼感到自在,恭喜您,現在您知道如何撰寫傳回函式的函式。