(Scala 六) 高阶函数

/**
  * 第6章 高阶函数
  */
//########################### 6.1 作为参数的函数 #################################
import scala.math._

/**
  * scala中,函数可以作为参数进行传递
  * 三中写法都可以
  */
def plus(x: Double) = 3 * x
Array(3.14, 1.42, 2.0).map(plus(_))
Array(3.14, 1.42, 2.0).map(plus _)
Array(3.14, 1.42, 2.0).map(plus)


/**
  * 将函数赋值给变量fun
  * 既然函数可以赋值到变量,那就该有类型,函数的类型为:(参数类型...)=>返回类型
  * 如fun类型: Double => Double
  */
val num = 3.14
//将函数赋值给变量fun
val fun = ceil _
//相当于把ceil()函数赋值到变量fun2上
val fun2 = ceil(_)
fun(num)
//将函数传递
Array(3.14, 1.42, 2.0).map(fun)




//########################### 6.2 匿名函数 #################################
/**
  * () {} 都可以
  */
Array(3.14, 1.42, 2.0).map((x: Double) => 3 * x)
Array(3.14, 1.42, 2.0).map { (x: Double) => 3 * x }

//########################### 6.3 高阶函数 #################################
/**
  * 能够接受函数作为参数的函数,叫做高阶函数
  */
def valueAtOneQuarter(f: (Double) => Double) = f(0.25)


/**
  * 高阶函数也可以返回函数
  * mulBy的函数类型: (Double) => ((Double) => Double)
  */
def mulBy(factor: Double) = (x: Double) => factor * x


val quintuple = mulBy(5)
//等同于
val quintuple2 = (x: Double) => 5 * x


quintuple(10)


//########################### 6.4 参数(类型)推断 #################################
/**
  * 匿名函数参数的类型推断
  */
//传入函数表达式
valueAtOneQuarter((x: Double) => 3 * x)
//参数推断省去类型信息
valueAtOneQuarter((x) => 3 * x)
//单个参数可以省去括号
valueAtOneQuarter(x => 3 * x)
//如果变量只在=>右边出现一次,可以用_来代替
valueAtOneQuarter(3 * _)

//########################### 6.5 闭包 #################################

/**
  * 闭包就是一个函数把外部的那些不属于自己的对象也包含(闭包)进来了
  * 匿名函数(x: Double) => factor * x 嵌套在函数mulBy中
  * 匿名函数(x: Double) => factor * x 使用了外部变量(即mulBy的局部变量factory)
  * mulBy2(3)时,triple将匿名函数的外部变量factor包了起来,形成一个"函数样板",因此trple、half这两个函数叫闭包
  * 闭包函数由代码合代码用到的非局部变量定义构成
  */
def mulBy2(factor: Double) = (x: Double) => factor * x

val triple = mulBy2(3)
val half = mulBy2(0.5)
println(triple(14) + " " + half(14))


//########################### 6.6 柯里化 #################################

/**
  * 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化
  * 柯里化就是证明了函数只需要一个参数而已
  */
//传统定义2个参数
def mul(x: Int, y: Int) = x * y
mul(6, 7)

//柯里化定义,使用到闭包
def mulOneAtTime(x: Int) = (y: Int) => x * y
mulOneAtTime(6)(7)
//相当于下面
val sixBei = mulOneAtTime(6)
sixBei(7)

//Scala中可以简写,参数也可以是函数
def mulOneAtTime2(x: Int)(y: Int) = x * y
mulOneAtTime2(6)(7)
//不能写下面
//val sixBei2 = mulOneAtTime2(6)
//sixBei2(7)


//柯里化的应用

//比如2个数组在某一对比条件下的对等性
val a = Array("Hello", "World")
val b = Array("hello", "world")

//corresponds函数定义使用了柯里化
a.corresponds(b)(_.equalsIgnoreCase(_))
// def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = {...}


//########################### 6.7 控制抽象函数 #################################
/**
  * 控制抽象是一类函数:
  * 1、参数是函数
  * 2、函数参数没有输入值,也没有返回值
  */
def runInThread(block: () => Unit): Unit = {
  new Thread {
    override def run() {
      block()
    }
  }.start()
}
println("Thread.currentThread().getName = " + Thread.currentThread().getName)
//传入函数
runInThread { () => println(Thread.currentThread().getName); println("Hi"); Thread.sleep(3000); println("Bye") }

//上面是匿名函数作为参数传入的写法,多行表达式需要用{}括起来,之间需要用;隔开,等同于下面这样,将一个函数传入runInThread(函数)中
val fun3 = { () => println(Thread.currentThread().getName); println("Hi"); Thread.sleep(3000); println("Bye"); }
runInThread(fun3)



/**
  * () => 有些多余,可以使用换名调用来表示,省略() 保留=>
  * 这种叫控制抽象函数(看上去像是编程语言关键字的函数)
  */
def runInThread2(block: => Unit): Unit = {
  new Thread {
    override def run() {
      block
    }
  }.start()
}
//优雅的传入
runInThread2 { println("Hi");  Thread.sleep(3000);  println("Bye") }

/**
  * 可以定义类似于while的until函数
  * 可以看出,until其内部逻辑已定好,它就像一个关键字一样抽象地控制传入函数的执行,所以叫控制抽象
  * 这里也用到了柯里化: def until(condition: => Boolean)(block: => Unit)
  * 没有用到闭包,因为x不是until的局部变量,而是一个全局变量
  */
def until(condition: => Boolean)(block: => Unit) {
  if (!condition) {
    block
    until(condition)(block)
  }
}

var x = 10
//unitl (condition) {block}
until(x == 0) {x -= 1; println(x) }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值