一、函数式编程
示例代码:
package matchDemo.function /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/11/17 * @time : 6:25 下午 * scala函数式编程 */ object FunctionOps1 { def main(args: Array[String]): Unit = { // 作为值的函数 funcOps1() // 匿名函数 funcOps2() // 高阶函数 funcOps3() } /* 函数可以作为值,传递给另外一个变量,或者另外一个函数 语法特点,必须要在函数后面加上空格或者下划线 */ def funcOps1(): Unit ={ def sayGoodBye(name:String): Unit ={ println("good bye to:"+name) } sayGoodBye("jack") // 传递给另外一个变量,用变量来调用 val sayBye = sayGoodBye _ sayBye("alex") //传递给另外一个函数 def sayBeyBey = sayGoodBye _ sayBeyBey("lili") } /* 所谓匿名函数,其实就是没有名字的函数 Scala定义一个完整函数: def funcName(params):returnType = {body} Scala定义一个匿名函数: (params) => {body} 匿名函数的实现 (params) => returnType 匿名函数的定义 问题是该匿名函数如何被调用 --> 只能将匿名函数赋值给另外一个变量或者函数来调用 */ def funcOps2(): Unit ={ // 定义一个匿名函数,并赋值给一个变量 val sayBey = (name:String) => { println("good bye to:"+name) } // 调用匿名函数 sayBey("alex") def sayBeyBey = (name:String) => { println("good bye to:"+name) } sayBeyBey("jone") } /* 所谓高阶函数:带函数参数的函数,一个函数的参数是函数,把这种函数称之为高阶函数(high level function) */ def funcOps3(): Unit ={ // 定义一个高阶函数 def sayBey(name:String,func:(String) => Unit): Unit ={ func(name) } // 调用函数sayBey sayBey("alex",(name:String) => method(name)) // 传递匿名函数 sayBey("pony",(name:String) => println(name)) // 简化书写 // 如果匿名函数中只有一个变量,可以省略掉() sayBey("cheery",name => println(name)) // 可以使用通配符"_"代替变量 sayBey("candy", println(_)) // 最简单可以连通配符"_"省略 sayBey("luzy", println) // 重新在调用上述函数 sayBey("gucci",method) } def method(str:String): Unit ={ println("一日之计在于晨") println(str) println("一年之计在于春") } }
运行结果:
good bye to:jack good bye to:alex good bye to:lili good bye to:alex good bye to:jone 一日之计在于晨 alex 一年之计在于春 pony cheery candy luzy 一日之计在于晨 gucci 一年之计在于春
二、高阶函数
示例代码:
package matchDemo.function /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/11/18 * @time : 10:33 上午 * Scala中常见的高阶函数,这些高阶函数都是作用在集合上面 * filter * map * flatmap * reduce * foreach * dropWhile * sortWith * groupBy * partitionBy */ object FunctionOps2 { def main(args: Array[String]): Unit = { filterOps() mapOps() flatMapOps() reduceOps() dropWhileOps() sortWithOps() groupByOps() partitionOps() } /* filter:过滤 filter:(A => Boolean) 过滤掉集合中元素A,经过函数操作,返回值为false的元素 */ def filterOps(): Unit ={ // 过滤掉集合中的偶数,留下集合中的奇数 val array = 1 to 10 var filtered = array.filter((num:Int) => num%2 != 0) println(filtered.mkString("[",",","]")) // 省略推断类型 filtered = array.filter((num) => num%2 != 0) println(filtered.mkString("[",",","]")) // 省略括号 filtered = array.filter(num => num%2 != 0) println(filtered.mkString("[",",","]")) // 使用通配符 filtered = array.filter(_ % 2 != 0) println(filtered.mkString("[",",","]")) } /* map:(p:A => B) 将一个集合中的所有元素A,都要作用在该匿名函数p上,每一个元素调用一次该匿名函数,将元素A最终转换成元素B 需要注意的是,A和B都是数据类型可以一致,也可以不一致 map操作其实就是一个one-2-one的映射操作 */ def mapOps(): Unit ={ val array = 1 to 5 // 将集合中的每一个元素扩大1.5倍 var newArr:IndexedSeq[Double] = array.map((num:Int) => num*1.5) println(newArr.mkString("[",",","]")) // 省略推断类型 newArr = array.map((num) => num*1.5) println(newArr.mkString("[",",","]")) // 省略括号 newArr = array.map(num => num*1.5) println(newArr.mkString("[",",","]")) // 使用通配符 newArr = array.map(_ * 1.5) println(newArr.mkString("[",",","]")) } /* flatmap ---> (f:A => Iterable(B)) flatmap和map的操作,比较相似,不同之处在于作用于匿名函数的返回值类型不一样 map操作是one-2-one flatmap操作是one-2-many,类似数据库中列转行的操作 ---------------------------------------------------------- foreach(p:A => Unit) 遍历集合中每一个元素A,进行操作,返回值类型为Unit */ def flatMapOps(): Unit ={ val array = Array( "i think there i am", "you are a lucky dog", "you are a green eye guy" ) // 提取集合中的每一个单词 var words = array.flatMap((line:String) => line.split(" ")) // 查看集合word中的数据,遍历 for(word <- words){ print(word+" ") } println("\r\n-----------------") // 省略推断类型 words = array.flatMap((line) => line.split(" ")) // 使用foreach遍历 words.foreach((word:String) => print(word + " ")) println("\r\n-----------------") // 使用通配符 words = array.flatMap(_.split(" ")) // 使用foreach遍历 words.foreach((word:String) => println(word + " ")) } /* reduce(p:(A1,A2) => A3) reduce是一个聚合函数,将2个A转换成1个A(其作用就是,作用在集合中的元素,进行聚合操作,得到一个新的值) var sum = 0 for (i <- array){ sum = sum + i } 此时,在每一次计算过程中的sum就是这里的A1,而i就是A2,sum和i聚合结束后的结果就是A3 此时的A3又作为下一次聚合操作中的sum,也就是A1 */ def reduceOps(): Unit ={ val array = 1 to 6 var sum = 0 for (i <- array){ println(s"sum=${sum},i=${i}") sum = sum + i } println("final sum is:"+sum) println("-----------------------------") sum = array.reduce((A1:Int,A2:Int) => { println(s"sum=${A1},i=${A2}") A1+A2 }) println("final sum is:"+sum) println("-----------------------------") sum = array.reduce((A1,A2) => { A1+A2 }) println("final sum is:"+sum) println("-----------------------------") sum = array.reduce(_ + _) // 最简形式 println("final sum is:"+sum) } /* dropWhile(p:A => Boolean) 该函数和filter一样,作用在集合的每一个元素,返回值为boolean类型 dropWhile删除元素,直到不满足条件位置 */ def dropWhileOps(): Unit ={ val array = Array(3,-6,7,1,3,4,-8,2) // 循环删除其中的偶数,直到条件不满足 var newArr = array.dropWhile((num:Int) => num%2 != 0) println(newArr.mkString("[",",","]")) } /* sortWith:排序操作 sortWith((A,A) => boolean) 返回值是boolean类型,同时sortWith是排序,显示就是要对这两个元素A进行大小比较,比较的结果就是boolean */ def sortWithOps(): Unit ={ val array = Array(3,-6,7,1,3,4,-8,2) // 对集合中的元素进行升序排序 var newArr = array.sortWith((v1,v2) => v1<v2) println(newArr.mkString("[",",","]")) newArr = array.sortWith(_ > _) println(newArr.mkString("[",",","]")) } /* groupBy就是SQL中的group by */ def groupByOps(): Unit = { val array = Array( "广东,广州", "广东,深圳", "广东,珠海", "浙江,杭州", "江苏,南京", "江苏,宿迁", "江苏,苏州", "湖北,武汉", "福建,福州", "江西,南昌", "山东,济南", "山东,青岛" ) /* 按照省份,对每一个城市进行分组 用sql: select province,city from xxx group by province; */ val province2Info:Map[String,Array[String]] = array.groupBy(line => line.substring(0,line.indexOf(","))) for ((province,cities) <- province2Info){ println(s"province:${province}--->${cities.mkString("[",",","]")}") } println("------------grouped------------------") // 将原来的集合进行分组,每个组内的元素有两个,或者可以理解为均分集合,每一份都是一个组 val arrays = array.grouped(2) for (arr <- arrays){ println(arr.mkString("[",",","]")) } } /* 将集合中的元素,按照一定的条件进行分组,最后分成两个组 partitionBy(p:A => boolean):(集合A,集合B) 在每一个元素A上进行作用该匿名函数,满足条件,共同构成返回值集合A, 不满足条件的共同构成返回值集合B 最后达到分区效果 */ def partitionOps(): Unit ={ val array = Array(3,-6,7,1,3,4,-8,2) // 将集合array,按照4进行分区,小于4的在一个分区中,大于等于4的在另一个分区 val (left,right) = array.partition((num:Int) => num <4) println(left.mkString("[",",","]")) println(right.mkString("[",",","]")) } }
运行结果:
[1,3,5,7,9] [1,3,5,7,9] [1,3,5,7,9] [1,3,5,7,9] [1.5,3.0,4.5,6.0,7.5] [1.5,3.0,4.5,6.0,7.5] [1.5,3.0,4.5,6.0,7.5] [1.5,3.0,4.5,6.0,7.5] i think there i am you are a lucky dog you are a green eye guy ----------------- i think there i am you are a lucky dog you are a green eye guy ----------------- i think there i am you are a lucky dog you are a green eye guy sum=0,i=1 sum=1,i=2 sum=3,i=3 sum=6,i=4 sum=10,i=5 sum=15,i=6 final sum is:21 ----------------------------- sum=1,i=2 sum=3,i=3 sum=6,i=4 sum=10,i=5 sum=15,i=6 final sum is:21 ----------------------------- final sum is:21 ----------------------------- final sum is:21 [-6,7,1,3,4,-8,2] [-8,-6,1,2,3,3,4,7] [7,4,3,3,2,1,-6,-8] province:浙江--->[浙江,杭州] province:广东--->[广东,广州,广东,深圳,广东,珠海] province:江苏--->[江苏,南京,江苏,宿迁,江苏,苏州] province:福建--->[福建,福州] province:湖北--->[湖北,武汉] province:江西--->[江西,南昌] province:山东--->[山东,济南,山东,青岛] ------------grouped------------------ [广东,广州,广东,深圳] [广东,珠海,浙江,杭州] [江苏,南京,江苏,宿迁] [江苏,苏州,湖北,武汉] [福建,福州,江西,南昌] [山东,济南,山东,青岛] [3,-6,1,3,-8,2] [7,4]
三、闭包和柯里化
示例代码:
package matchDemo.function /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/11/18 * @time : 4:49 下午 * scala函数操作之 * 闭包 * 柯里化 */ object FunctionOps3 { def main(args: Array[String]): Unit = { // 闭包 closureOps() // 柯里化 curringOps() } def closureOps(): Unit ={ // 定义一个匿名函数,赋值给了一个有参的函数,匿名函数内部的实现需要前面定义的参数 def mulBy(factor:Double) = (x:Double) => factor * x val triple = mulBy(3.0) val half = mulBy(0.5) /* mulBy的函数体是通过一个匿名函数来实现的 而该匿名函数(x:Double) => factor * x,需要一个参数factor,并没有赋值,而该factor来自于前面的函数 程序的执行过程: 首先,在代码中定义了两个函数 第一个是mulBy 第二个是匿名函数(x:Double) => factor * x 其次,执行函数mulBy,并赋值给triple,这样,首先就将factor值赋值成3.0 函数执行完毕之后,是不是就进行弹栈,mulBy的实现匿名函数。 再其次,匿名函数(x:Double) => factor * x压栈,factor是不是就将刚才的3.0保存到自己的局部变量中 最后,调用它的triple(42)的时候,42传递给了x,最终结果就是42 * 3 = 126 在这个过程中,最后,匿名函数调用了一个不再其作用于范围内的变量factor,先弹栈,然后将factor保存到了 匿名函数,最后在匿名函数中调用了factor。 把这种结构称之为闭包——函数可以在变量不处于其作用域范围内被调用。 */ println(triple(42) + "-------" + half(42)) } /* 柯里化: 原来的函数有两个参数,def sum(x:Int,y:Int) = x+y 现在将sum函数进行改变,只保留其中一个参数,另外一个参数作为一个新的匿名函数的参数列表而存在 通常该sum函数的函数体就是该匿名函数 把这个过程称之为柯里化 一个很重要的操作就是降维,降低参数的个数,维度 */ def curringOps(): Unit ={ def sum(x:Int,y:Int) = x+y // 进行柯里化改造 def total(x:Int) = (y:Int) => x+y println(total(3)(4)) } }
运行结果:
126.0-------21.0 7