Scala函数式编程高阶
Scala函数式编程高阶
偏函数
/**
* 需求:val list = List(1,2,3,4,"abc")
* 给一个集合,将集合中所有数字 + 1,并返回一个新的集合
* 要求忽略掉非数字的元素,即返回新的集合形式为(2,3,4,5)
*/
object Hello {
def main(args: Array[String]): Unit = {
//思路一:模式匹配,不够完美
val list = List(1,2,3,"a",5)
val res = list.map(addOne)
println(res)
//filter + map
val list2 = List(1,2,3,"a",5)
val res2 = list2.filter(f1).map(f3).map(f2).foreach(x => print(x + " "))
}
def addOne(i: Any) = {
i match {
case x: Int => x+1
case _ =>
}
}
def f1(n: Any): Boolean = {
n.isInstanceOf[Int]
}
def f2(n: Int): Int = {
n + 1
}
def f3(n: Any): Int = {
n.asInstanceOf[Int]
}
}
使用偏函数来解决
/**
* 使用偏函数说明
* 如果使用偏函数,则不能使用map,应该使用collect
* 偏函数执行流程
* 1.遍历list所有元素
* 2.然后调用val ele = if(partialFunction.isDefinedAt(list单个元素)){
* partialFunction.apply(list单个元素)
* }
* 3.得到一个ele,放入到新的集合,最后返回
*/
object Hello {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,"a",5)
//1.PartialFunction[Any, Int] 表示偏函数接收的参数类型时Any,返回类型时Int
//2.isDefinedAt如果返回true,就会去调用apply构建对象实例,如果false,过滤
//3.apply构造器,对传入的值 +1,并返回
val partialFunction = new PartialFunction[Any, Int] {
override def isDefinedAt(x: Any): Boolean = {
println("x = " + x)
x.isInstanceOf[Int]
}
override def apply(v1: Any): Int = {
println("v1 = " + v1)
v1.asInstanceOf[Int] + 1
}
}
val list2 = list.collect(partialFunction)
println(list2)
}
}
匿名函数
def main(args: Array[String]): Unit = {
//1.不需要些def函数名
//2.不需要些返回类型,使用类型推导
//3.如果有多行,则使用{}包括
val triple = (x: Double) => {
println("x = " + x)
3 * x
}
println("triple " + triple(3))
}
高阶函数
能够接收函数作为参数的函数,叫做高阶函数。可使应用程序更加健壮。
高阶函数的基本使用
object Hello {
def main(args: Array[String]): Unit = {
val res = test(sum,mod,5.0)
println("res: " + res)
}
def test(f: Double => Double, f2: Double => Int,n1: Double) = {
f(f2(n1))
}
def sum(d: Double): Double = d + d
def mod(d: Double): Int = d.toInt % 2
}
高阶函数作为返回函数类型
object Hello {
def main(args: Array[String]): Unit = {
val f1 = minusxt(3)
println("f1的类型 = " + f1)
println(f1(2)) //1
println(f1(9)) //-6
}
def minusxt(x: Int) = {
//返回的是一个函数
(y: Int) => x - y
}
}
参数(类型)推断
参数推断省去类型信息(在某些情况下,参数类型是可以推断出来的,如list = (1,2,3) list.map() map中函数参数类型是可以推断的),同时也可以进行相应的简写
1)参数类型是可以推断时,可以省略参数类型
2)当传入的函数,只有单个参数时,可以省去括号
3)当变量只在=>右边只出现一次,可以用_来代替
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
println(list.map((x: Int) => x+1))
println(list.map((x) => x+1))
println(list.map(x => x+1))
println(list.map(_ + 1))
println(list.reduce((n1: Int, n2: Int) => n1 + n2 ))
println(list.reduce((n1, n2) => n1 + n2))
println(list.reduce(_ + _))
}
闭包
闭包就是一个函数和与其相关的引用环境组合的一个整体
def main(args: Array[String]): Unit = {
val f = minusxy(20)
println(f(1))
val suffix = makeSuffix(".jpg")
println(suffix("xx"))
}
def minusxy(x: Int) = {
//返回的时一个匿名函数,因为该函数引用到函数外的x,那么该函数和x整体形成一个闭包
(y: Int) => x - y
}
/**
* 闭包案例
* 编写一个函数,makeSuffix(suffix: String)可以接收一个文件后缀名(比如:.jpg)并返回一个闭包
* 调用一个闭包,可以传入一个文件名,如果该文件名没有制定的后缀,则返回文件名.jpg,如果有直接返回源文件
*/
def makeSuffix(suffix: String) = {
(filename: String) => {
if (filename.endsWith(suffix)) filename else filename + suffix
}
}
函数柯里化
函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化
//函数柯里化在隐式转换中使用特别广泛
def mul(x: Int, y: Int) = x * y
//将函数柯里化
def mulCurry(x: Int)(y: Int) = x * y
递归函数
Scala非常推崇递归的编程思想
def test(n: Int): Unit = {
if (n > 2){
test(n-1) //n-1 就是为了向递归结束逼近
}
println("n = " + n)
}
//test(4) 输出 2,3,4
//我们可以使用栈来分析
//当程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
//递归必须向退出递归的条件逼近,否则就会进入无限递归
//当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁
def test2(n: Int): Unit = {
if (n > 2){
test2(n-1)
}else{
println("n = " + n)
}
}
//test2(4) 输出2
def myMax(l: List[Int]): Int = {
if (l.isEmpty) throw new java.util.NoSuchElementException("傻逼")
if (l.size == 1) l.head
//递归是告诉计算做什么,而不是告诉计算怎么做
else if (l.head > myMax(l.tail)) l.head else myMax(l.tail)
}
def myReverse(s: String): String = {
if (s.isEmpty) throw new java.util.NoSuchElementException("傻逼")
if (s.size == 1) s
else myReverse(s.tail) + s.head
}
def myFib(n: Long): Long = {
if (n == 1 ) n
else n * myFib(n-1)
}
//递归使用的陷进
var count: BigInt = 0
def fbn(n: BigInt): BigInt = {
count += 1
if (n==1 || n==2) 1
//当遇到重复计算的时候,一定要注意优化
else fbn(n-1) + fbn(n-2)
}