由于 Scala 的一致性,编写一个返回函数的方法与您在前几节中看到的所有内容相似。
例如,假设您想编写一个返回函数的 greet
方法。
我们再次从问题陈述开始:
我想创建一个返回函数的
greet
方法。 该函数将接受一个字符串参数并使用println
打印它。 为了简化第一个示例,greet
不会接受任何输入参数;它只会构建一个函数并返回它。
鉴于该声明,您可以开始构建 greet
。
你知道这将是一种方法:
def greet()
您还知道此方法将返回一个函数,该函数 (a) 采用 String
参数,并且 (b) 使用 println
打印该字符串。
因此,该函数的类型为 String => Unit
:
def greet(): String => Unit = ???
----------------
现在你只需要一个方法体。 您知道该方法需要返回一个函数,并且该函数接受一个“字符串”并打印它。 此匿名函数与该描述匹配:
(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"你好,$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"
如果你对这段代码感到满意——恭喜——你现在知道如何编写返回函数的方法了。
Contributors to this page:
Contents
- 导言
- Scala 3 特性
- 为什么是 Scala 3 ?
- Scala 的味道
- Hello, World!
- The REPL
- 变量和数据类型
- 控制结构
- 领域建模
- 方法
- 头等函数
- 单例对象
- 集合
- 上下文抽象
- 顶层定义
- 总结
- 类型初探
- 字符串插值
- 控制结构
- 领域建模
- 工具
- OOP 领域建模
- 函数式领域建模
- 方法
- 方法特性
- main 方法
- 总结
- 函数
- 匿名函数
- 函数变量
- Eta 扩展
- 高阶函数
- 自定义 map 函数
- 创建可以返回函数的方法
- 总结
- 打包和导入
- Scala 集合
- 集合类型
- 集合方法
- 总结
- 函数式编程
- 什么是函数式编程?
- 不可变值
- 纯函数
- 函数是值
- 函数式错误处理
- 总结
- 类型和类型系统
- 类型推断
- 泛型
- 相交类型
- 联合类型
- 代数数据类型
- 型变
- 不透明类型
- 结构化类型
- 依赖函数类型
- 其他类型
- 上下文抽象
- 扩展方法
- Given 实例和 Using 语句
- 上下文绑定
- Given 导入
- 实现类型类
- 多元相等性
- 隐式转换
- 总结
- 并发
- Scala 工具
- 使用 sbt 构建和测试 Scala 项目
- worksheet
- 与 Java 交互
- 向 Java 开发者介绍Scala
- Scala for JavaScript Developers
- Scala for Python Developers
- 下一步去哪