13 Scala 函数式编程高级

函数式编程高级

1. 偏函数

1.1 快速入门

val list = List(1, 2, 3, 4, "hello")

//定义一个偏函数
//1. PartialFunction[Any,Int] 表示偏函数接收的参数类型是 Any,返回类型是 Int 
//2. isDefinedAt(x: Any) 如果返回 true ,就会去调用 apply 构建对象实例,如果是 false,过滤 
//3. apply 构造器 ,对传入的值 + 1,并返回(新的集合)
val partialFun = new PartialFunction[Any,Int] {
  override def isDefinedAt(x: Any) = { 
    x.isInstanceOf[Int] 
  }
  override def apply(v1: Any) = { 
    v1.asInstanceOf[Int] + 1 
  } 
}

//使用偏函数
//1. 遍历 list 所有元素 
//2. 然后调用 val element = if(partialFun-isDefinedAt(list 单个元素)) {partialFun-//apply(list 单个元 素) }
//3. 每得到一个 element,放入到新的集合,最后返回
val list2 = list.collect(partialFun) 
println("list2" + list2)   // (2,3,4,5)

1.2 小结

  1. 使用构建特质的实现类(使用的方式是 PartialFunction 的匿名子类) 。
  2. PartialFunction 是个特质(看源码) 。
  3. 构建偏函数时,参数形式 [Any, Int] 是泛型,第一个表示参数类型,第二个表示返回参数 。
  4. 当使用偏函数时,会遍历集合的所有元素,编译器执行流程时先执行 isDefinedAt() 如果为 true , 就会执行 apply , 构建一个新的 Int 对象返回 。
  5. 执行 isDefinedAt()false 就过滤掉这个元素,即不构建新的 Int 对象。
  6. map 函数不支持偏函数,因为 map 底层的机制就是所有循环遍历,无法过滤处理原来集合的元素 。
  7. collect 函数支持偏函数。

1.3 偏函数的简写形式

// 方式1:简写成 case 语句
def partialFun2: PartialFunction[Any,Int] = { 
  case i:Int => i + 1 
}

// 方式2
val list3 = list.collect{ case i:Int => i + 1 }

2. 作为参数的函数

2.1 基本介绍

  1. 函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是:function1

    即:(参数类型) => 返回类型

2.2 案例

def plus(x: Int) = 3 + x 

val result1 = Array(1, 2, 3, 4).map(plus(_)) 
println(result1.mkString(","))   // (4,5,6,7)
  1. map(plus(_)) 中的 plus(_) 就是将 plus 这个函数当做一个参数传给了 map_ 这里代表从集合中遍历出来的一个元素。
  2. plus(_) 这里也可以写成 plus 表示对 Array(1,2,3,4) 遍历,将每次遍历的元素传给 plusx
  3. 进行 3 + x 运算后,返回新的 Int ,并加入到新的集合 result1 中。
  4. def map[B, That](f: A => B) 的声明中的 f: A => B 表示一个函数。

3. 匿名函数

3.1 基本介绍

  1. 没有名字的函数就是匿名函数,可以通过函数表达式来设置匿名函数。

  2. 不需要写 def 函数名

  3. 不需要写返回类型,使用类型推导。

  4. = 变为 =>

  5. 函数体如果有多行,使用 {} 包括。

3.2 案例

val triple = (x: Double) => { 3 * x }

print(triple(3))   // 9

4. 高阶函数

4.1 基本介绍

  1. 能够接受函数作为参数的函数,叫做高阶函数。

4.2 基本使用

// 定义高阶函数
def test(f: Double => Double, num: Double) {
  f(num)
}
// 定义普通函数
def sum(n: Double) {
  n + n
}

// 使用
val res = test(sum, 3.0)
print(res)  // 9.0

4.3 高阶函数可以返回函数类型

// 1. minusxy 是高阶函数,因为它返回匿名函数 
// 2. 返回的匿名函数 (y: Int) => x - y 
// 3. 返回的匿名函数可以使用变量接收

def minusxy(x: Int) {
  (y: Int) => x - y
}

// 使用 方式一
val f = minusxy(3)
val res = f(1)  // 2

// 使用 方式二
val res = minusxy(3)(2)  // 2

5. 参数类型推断

5.1 基本介绍

  1. 参数推断省去类型信息,参数类型是可以推断出来的,如 list=(1,2,3) list.map()map 中函数参数类型是可以推断的,同时也可以进行相应的简写。

5.2 参数类型推断写法说明

  1. 参数类型是可以推断时,可以省略参数类型。
  2. 当传入的函数,只有单个参数时,可以省去括号。
  3. 如果变量只在 => 右边只出现一次,可以用 _ 来代替。

5.3 案例

val list = List(1, 2, 3, 4) 
println(list.map((x:Int)=>x + 1)) //(2,3,4,5) 
println(list.map((x)=>x + 1)) //(2,3,4,5) 
println(list.map(x=>x + 1)) //(2,3,4,5) 
println(list.map( _ + 1)) //(2,3,4,5)

def f1(n1:Int ,n2:Int): Int = { 
  n1 + n2 
}
println(list.reduce(f1)) // 10 
println(list.reduce((n1:Int ,n2:Int) => n1 + n2)) //10 
println(list.reduce((n1 ,n2) => n1 + n2)) //10 
println(list.reduce(_ + _)) //10 

6. 闭包

6.1 基本介绍

  1. 闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)。

6.2 案例

def minusxy(x: Int) = (y: Int) => x - y
//f 函数就是闭包. 
val f = minusxy(20) 
println("f(1)=" + f(1)) // 19 
println("f(2)=" + f(2)) // 18
  1. (y: Int) => x – y 返回的是一个匿名函数 ,因为该函数引用到到函数外的 x ,那么该函数和 x 整体形成一个闭包。 如:这里 val f = minusxy(20)f 函数就是闭包。
  2. 可以这样理解,返回函数是一个对象,而 x 就是该对象的一个字段,他们共同形成一个闭包。
  3. 当多次调用 f 时(可以理解多次调用闭包),发现使用的是同一个 x , 所以 x 不变。
  4. 在使用闭包时,主要搞清楚返回函数引用了函数外的哪些变量,因为他们会组合成一个整体(实体),形成一个闭包。

7. 函数柯里化

7.1 基本介绍

  1. 函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化。
  2. 柯里化就是证明了函数只需要一个参数而已。

7.2 案例

// 编写一个函数,接收两个整数,可以返回两个数的乘积

// 使用常规的方式完成 
def mul(x: Int, y: Int) = x * y 
println(mul(10, 10))

// 使用闭包的方式完成
def mulCurry(x: Int) = (y: Int) => x * y 
println(mulCurry(10)(9))

// 使用函数柯里化完成
def mulCurry2(x: Int)(y:Int) = x * y 
println(mulCurry2(10)(8))

8. 控制抽象

8.1 基本介绍

  1. 参数是函数。
  2. 函数参数没有输入值,也没有返回值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值