Scala 3 — 书籍

创建返回函数的方法

语言

由于 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"

如果您对该代码感到满意,那么恭喜您,您现在知道如何编写返回函数的方法。

此页面的贡献者