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
}
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长