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)
}
posted @ 2019-02-19 20:47  刘丽刚  阅读(198)  评论(0)    收藏  举报