ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

scala之旅-核心语言特性【高阶函数】(十)

2020-10-27 13:35:10  阅读:211  来源: 互联网

标签:salary 函数 之旅 scala Double List salaries 高阶 String


高阶函数是将其他函数作为形参,或者以函数作为返回结果。因为在Scala中,函数是一等公民。这个术语可能听起来有点乱,但实际上我们把 以函数作为形参或以函数作为返回结果的函数和方法统称为高阶函数。

在一个纯粹的面向对象编程中,隐藏可能会暴露对象内部状态的参数是一个很好的解决方案,泄漏内部状态可能会破坏对象的内部的不变性。从而导致违反封装性原则。

一个最常用的案例就是高阶函数 map,在scala中经常用于处理集合的。

val salaries = Seq(20000, 70000, 40000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)

doubleSalary 是一个函数,这个函数一个 Int 类型的x 作为形参,然后返回 x*2 。一般情况下,=> 左边的元组是一个参数列表,右边则是一个返回的表达式。在第3行,函数 doubleSalary 将作用于 salaries 中的每一个元素。

为了简化这段代码,我们可以使用一个匿名函数作为实参直接传给map。

val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)

注意,x 没有在上面的例子中直接声明为 Int 类型。这是因为可以根据 map的期望的函数类型直接推断出 x的类型(参见 currying,编写如上这段代码更惯用的方式)。

val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(_ * 2)

因为Scala编译器已经知道了参数的类型了(一个单独的Int)。你只需要在右边提供一个函数。值得注意的是,你可以用一个 _ 来代替形参名 (这个就等价于之前例子中的 x)。

将方法强转为函数

当然也可以将方法作为实参传递给高阶函数。因为Scala编译器会将方法强转为函数.

case class WeeklyWeatherForecast(temperatures: Seq[Double]) {

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

  def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- passing the method convertCtoF
}

这里的 convertCtoF 可以被用来传递给高阶函数map. 这是因为编译器将方法 convertCtoF 强转为函数 x => convertCtoF(x) (注意,x 是一个生成的名字,并且保证其在作用域内是唯一的)

接收函数的函数

使用高阶函数的一个原因是为了减少冗余的代码。假设,你想实现一些方法,这些方法根据一些特征来实现提高某人的薪资。在不使用高阶函数的时候,代码可能看起来像下面这个

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)
}

注意,每一个方法只随乘数变化而变化。为了简化,你可以将重复的代码抽到高阶函数里面去,如下:

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 greatPromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * math.log(salary))

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

这个新方法 promition 将 salaries 和一个 Double => Double 函数作为形参 (函数以Double作为参数,Double作为返回值) 并返回乘积。

方法和函数通常用于描述行为和数据的变化。因此用函数去构建其他函数有助于搭建通用的框架。这些通用的操作延迟了整个行为的锁定,从而为客户端提供提供了可控的或者将来可自定义的部分提供了可能。

函数返回函数

在某些情况下你可以生成一些函数。如下的例子就是返回一个函数

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) // "https://www.example.com/users?id=1": String

注意 urlBuilder返回的类型是 (String,String) => String 。这意味着返回的匿名函数需要传递两个String参数,然后返回一个String值。在这种情况下,返回的匿名函数为(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"

标签:salary,函数,之旅,scala,Double,List,salaries,高阶,String
来源: https://www.cnblogs.com/zhouwenyang/p/13883454.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有