12 高阶函数

【12 高阶函数】
文章目录

    • 作为值的函数
    • 匿名函数
    • 带函数参数的函数
    • 参数类型推断
    • 一些有用的高阶函数
    • 闭包
    • SAM转换
    • 柯里化

作为值的函数
  • 变量中存放函数
  • 将方法变为函数
import scala.math._ val num = 3.45 val fun = ceil _//这里的 _ 表示这个函数,而不是没有传参数 //或 val fun = ceil(_) //fun: Double => Double = println(fun(3.45))

  • ceil是math这个包对象的方法,如果有来自类的方法,将其变成函数的方式
scala> val f = (_:String).charAt(_:Int) f: (String, Int) => Char = scala> val f1:(String,Int)=>Char = _.charAt(_) f1: (String, Int) => Char = scala> val add : (Int,Int)=>Int = (x,y)=>x+y add: (Int, Int) => Int =

  • 可以对函数调用传递(存放在变量中或作为参数传递给另一个函数)
scala> fun(3.13) res10: Double = 4.0scala> Array(3.1,3.4,5.7).map(fun) res11: Array[Double] = Array(4.0, 4.0, 6.0)

匿名函数
  • 函数不一定有名字,就像数字也不一定有名字
  • 以def定义的都是方法,不是函数
  • 结合第二章的内容
  • 函数名的后面有时候是冒号有时候是等号。如果右侧显式指明函数的类型就用冒号,如果不显式指明函数的类型就用等号,函数类型可以通过自动推断得到
scala> (x:Double) => 3*x res12: Double => Double = //或者加名字 scala> val triple=(x:Double) => 3*x triple: Double => Double = scala> val triple1:(Double)=>Double =3*_ triple1: Double => Double = scala> val triple1:(Double)=>Double = x => 3*x triple1: Double => Double = //使用map,map后面也可以跟大括号 scala> Array(3.1,3.4,5.7).map(triple1) res13: Array[Double] = Array(9.3, 10.2, 17.1) scala> Array(3.1,3.4,5.7).map{triple1} res14: Array[Double] = Array(9.3, 10.2, 17.1)

带函数参数的函数
  • 函数作为参数
  • 高阶函数:函数作为参数或返回值
  • 如下示例
//函数作为参数 def valueAtQuator(f:(Double)=>Double):Double = f(0.25) //(f: Double => Double)Double //函数作为返回值 def mulBy(factor:Double):Double=>Double = {(x:Double)=>factor*x} //Double => Double =

参数类型推断
  • scala会自动类型推断
  • 给出_的类型有助于将方法变为函数
//手动指明类型 scala> valueAtQuator((x:Double) => 3*x) res19: Double = 0.75 //scala自动推断x的类型 scala> valueAtQuator((x) => 3*x) res20: Double = 0.75 //只有一个参数的时候,略去x的括号 scala> valueAtQuator(x => 3*x) res21: Double = 0.75 //如果x在=>右边只出现了一次,可以用_代替 scala> valueAtQuator(3*_) res22: Double = 0.75scala> (_:String).substring(_:Int,_:Int) res0: (String, Int, Int) => String =

一些有用的高阶函数
  • 练习scala集合库中的一些接受函数参数的方法
  • foreach 将函数应用到每个元素,不返回值
  • filter交出所有满足条件的元素
  • reduceLeft
scala> (1 to 9).map("*"*_).foreach(println) * ** *** **** ***** ****** ******* ******** *********scala> (1 to 9).filter( _ % 2 ==0) res3: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)scala> (1 to 9).map(_.toString).reduceLeft( (x,y) => (s"f(${x},${y})")) res8: String = f(f(f(f(f(f(f(f(1,2),3),4),5),6),7),8),9)scala> (1 to 9).map(_.toString).reduceRight( (x,y) => (s"f(${x},${y})")) res9: String = f(1,f(2,f(3,f(4,f(5,f(6,f(7,f(8,9))))))))scala> Array(4,1,2,6).sortWith(_<_) res11: Array[Int] = Array(1, 2, 4, 6)

闭包
  • 闭包由代码和代码用到的任何非局部变量定义构成
  • 下面的示例中,每一个函数都有自己的factor设置
def mulBy(factor:Double):Double=>Double = {(x:Double)=>factor*x}scala> def triple = mulBy(3) triple: Double => Doublescala> def hale = mulBy(0.5) hale: Double => Double

SAM转换
  • Single Abstract method 带有单个抽象方法
  • scala函数到java SAM接口转换只对函数字面量有效
柯里化
  • 将原来接受两个参数的函数变成新的接受一个参数的函数的过程,新的函数返回一个以原有第二个参数作为参数的函数。
scala> val mul = (x:Int,y:Int)=>x*y mul: (Int, Int) => Int = scala> val mulOneATime =(x:Int)=>((y:Int)=>x*y) mulOneATime: Int => (Int => Int) = scala> mulOneATime(6)(7) res12: Int = 42 //柯里化简化版 方法 scala> def mulOneATime1 (x:Int)(y:Int)=x*y mulOneATime1: (x: Int)(y: Int)Int //柯里化函数版 scala> val mulOneATime2 = (x:Int) => (y:Int)=>x*y mulOneATime2: Int => (Int => Int) =

  • 柯里化把某个函数参数单独提出来,以提供更多用于类型推断的信息
  • _.equalsIgnoreCase(_)是一个经过柯里化的参数的形式传递
scala> val a = Array("hello","world") a: Array[String] = Array(hello, world)scala> val b = Array("Hello","world") b: Array[String] = Array(Hello, world)scala> a.corresponds(b)(_.equalsIgnoreCase(_)) res13: Boolean = true //corresponds源码 def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = { val i = this.iterator val j = that.iterator while (i.hasNext && j.hasNext) if (!p(i.next(), j.next())) return false!i.hasNext && !j.hasNext }

    推荐阅读