前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >8.scala高阶函数

8.scala高阶函数

作者头像
Spark学习技巧
发布2021-03-05 14:40:33
4840
发布2021-03-05 14:40:33
举报
文章被收录于专栏:Spark学习技巧Spark学习技巧

高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。这里的术语可能有点让人困惑,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。

最常见的一个例子是Scala集合类(collections)的高阶函数map

代码语言:javascript
复制
val salaries = Seq(20000, 70000, 40000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary)

函数doubleSalary有一个整型参数x,返回x * 2。一般来说,在=>左边的元组是函数的参数列表,而右边表达式的值则为函数的返回值。在第3行,函数doubleSalary被应用在列表salaries中的每一个元素。

为了简化压缩代码,我们可以使用匿名函数,直接作为参数传递给map:

代码语言:javascript
复制
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(x => x * 2) 

注意在上述示例中x没有被显式声明为Int类型,这是因为编译器能够根据map函数期望的类型推断出x的类型。对于上述代码,一种更惯用的写法为:

代码语言:javascript
复制
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(_ * 2)

既然Scala编译器已经知道了参数的类型(一个单独的Int),你可以只给出函数的右半部分,不过需要使用_代替参数名(在上一个例子中是x

强制转换方法为函数

你同样可以传入一个对象方法作为高阶函数的参数,这是因为Scala编译器会将方法强制转换为一个函数。

代码语言:javascript
复制
case class WeeklyWeatherForecast(temperatures: Seq[Double]) {

  private def convertCtoF(temp: Double) = temp * 1.8 + 32

  def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) 
}

在这个例子中,方法convertCtoF被传入forecastInFahrenheit。这是可以的,因为编译器强制将方法convertCtoF转成了函数x => convertCtoF(x) (注: x是编译器生成的变量名,保证在其作用域是唯一的)。

接收函数作为参数的函数

使用高阶函数的一个原因是减少冗余的代码。比方说需要写几个方法以通过不同方式来提升员工工资,若不使用高阶函数,代码可能像这样:

代码语言:javascript
复制
object SalaryRaiser {

  def smallPromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * 1.1)

  def greatPromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * math.log(salary))

  def hugePromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * salary)
}

注意这三个方法的差异仅仅是提升的比例不同,为了简化代码,其实可以把重复的代码提到一个高阶函数中:

代码语言:javascript
复制
object SalaryRaiser {

  private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
    salaries.map(promotionFunction)

  def smallPromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * 1.1)

  def bigPromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * math.log(salary))

  def hugePromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * salary)
}

新的方法promotion有两个参数,薪资列表和一个类型为Double => Double的函数(参数和返回值类型均为Double),返回薪资提升的结果。

返回函数的函数

有一些情况你希望生成一个函数, 比如:

代码语言:javascript
复制
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
  val schema = if (ssl) "https://" else "http://"
  (endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
}

val domainName = "www.example.com"
def getURL = urlBuilder(ssl=true, domainName)
val endpoint = "users"
val query = "id=1"
val url = getURL(endpoint, query)

注意urlBuilder的返回类型是(String, String) => String,这意味着返回的匿名函数有两个String参数,返回一个String。在这个例子中,返回的匿名函数是

代码语言:javascript
复制
(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浪尖聊大数据 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 强制转换方法为函数
  • 接收函数作为参数的函数
  • 返回函数的函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档