Scala偏函数
仿写函数式编程
- 仿写函数式编程
def main(args: Array[String]): Unit = {
println("===test01函数===")
test01
println("===testMyForeach函数===")
testMyForeach
println("===testMyMap函数===")
testMyMap
println("===testMyFilter函数===")
testMyFilter
println("===testMyReduce函数===")
testMyReduce
}
/*常规写法(使用高阶函数实现每个元素 * 3)*/
def test01() = {
val list = List(1,2,3,4,5,6)
list.map(_ * 5).foreach(println)
}
// 用函数式编程实现foreach
def myForeach(array:Array[Int], op:Int=>Unit) = {
for(ele <- array){
op(ele)
}
}
// 测试myForeach函数
def testMyForeach() = {
val array = Array(1,2,3,4,5,6,7,8,9)
myForeach(array, println)
}
// 用函数式编程实现Map
def myMap(array:Array[Int], op:Int => Int) = {
/*for(ele <- array){ // 这样写不对,for没有返回值
op(ele)
}*/
for(ele <- array) yield op(ele) // 返回Array[Int]
}
// 测试myMap函数
def testMyMap() = {
val array = Array(1,2,3,4,5,6,7,8,9)
myMap(array, x => x * 2).foreach(println)
}
// 用函数式编程实现Filter
def myFilter(array:Array[Int], op:Int => Boolean) = {
for(ele <- array if op(ele)) yield ele
}
// 测试myFilter函数
def testMyFilter() = {
val array = Array(1,2,3,4,5,6,7,8,9)
myFilter(array, x => x % 3 == 0).foreach(println)
}
// 用函数式编程实现reduce
def myReduce(array:Array[Int], op:(Int,Int) => Int) = {
var firstEle = array(0) // 获取到第一个元素
for(ele <- 1 until(array.length)) {
firstEle = op(firstEle, array(ele))
}
firstEle
}
// 测试myReduce函数
def testMyReduce() = {
val array = Array(1,2,3,4,5,6,7,8,9)
println(myReduce(array, _ + _))
}
偏函数【重要知识点】
官方文档:https://docs.scala-lang.org/overviews/quasiquotes/expression-details.html#partial-function
1. 偏函数PartialFunction概念
- Partial functions are a neat syntax that let you express functions with a limited domain by using pattern matching
2. 偏函数完成模式匹配的改写
- 下面的代码比较细,分别用了6种方案,从(步骤多)到(步骤少)的改写,但是代码的理解上,却是从简单到难的增加,所以需要一步一步去理解,然后记住结论。
- 最后一种test06最简单,其实使用的就是PartialFunction的原理(如果想要运行代码,可以下面全部拷贝)
// match的一般写法
def test01() = {
var brands = Array("Scala","Q7","X6","GLE450")
1.to(5).foreach(x =>{
val brand = brands(Random.nextInt(brands.length))
brand match {
case "Q7" => println("Q7")
case "X6" => println("X6")
case "GLE450" => println("GLE450")
case _ => println("雅迪电动车,你知道拥有")
}
})
}
- 第 1 次改写
/**
* 偏函数完成模式匹配的改写
* 由复杂到简单第 1 次改写 【步骤繁琐】
*/
def test02 = {
// PartialFunction[String,String], 输入是String, 返回也是String类型
// PartialFunction的初级写法,结合case来改造
def partialTest:PartialFunction[String,String] = {
case "Q7" => "Q7"
case "X6" => "X6"
case "GLE450" => "GLE450"
case _ => "雅迪电动车,你知道拥有"
}
// 测试partialTest是否可以正常输出,PartialFunction的初级写法功能是否正常
println(partialTest("GLE450"))
}
- 第 2次改写
/**
* 偏函数完成模式匹配的改写
* 由复杂到简单第 2 次改写【步骤繁琐】
*/
def test03() = {
val list = List(1,2,3,Boolean,"Scala" ,3.0D)
// 1)抓取上面List中Int类型的值
def f1(ele: Any) = ele.isInstanceOf[Int]
// list.filter(f1).foreach(println) // 输出结果:1,2,3 【Any类型】
// 2)将Any转换成int值
def f2(ele:Any) = ele.asInstanceOf[Int]
// list.filter(f1).map(f2).foreach(println) // 输出结果:1,2,3【Int类型】
// 3)将Int值 * 5
def f3(i:Int) = i * 5
list.filter(f1).map(f2).map(f3).foreach(println) // 输出结果:5,10,15【Int类型】
}
- 第 3 次改写
/**
* 偏函数完成模式匹配的改写
* 由复杂到简单第 3 次改写【步骤繁琐】
*/
def test04() = {
val list = List(1,2,3,Boolean,"Scala" ,3.0D)
val fun = new PartialFunction[Any, Int] {
//PartialFunction参数[Any, Int] ,Any表示上面List中可能存在Any类型的值,只过来其中Int类型的值
// PartialFunction是个接口,需要自动重写下面两个方法。
// 抓取Int的值
override def isDefinedAt(x: Any): Boolean = {
if(x.isInstanceOf[Int]){ // 不推荐省略{ },万一需要写其他逻辑,容易写错
true
}else{
false
}
}
// 将isDefinedAt得到的结果 (v1:Any) * 5
override def apply(v1: Any): Int = v1.asInstanceOf[Int] * 5
}
// 偏函数的调用:collect
list.collect(fun).foreach(println)
}
- 第 4 次改写
- 借助了case匹配的方式
- 偏函数的调用:collect
/**
* 偏函数完成模式匹配的改写
* 由复杂到简单第 4 次改写【步骤繁琐】
*/
def test05() = {
val list = List(1,2,3,Boolean,"Scala" ,3.0D)
val fun:PartialFunction[Any, Int] = {
case i:Int => i * 5 // 借助了case匹配的方式,自动完成了Int的判断
}
// 偏函数的调用:collect
list.collect(fun).foreach(println)
}
- 第 5 次改写(collect后面直接用匿名函数,不再单独定义PartialFunction函数)
/**
* 偏函数完成模式匹配的改写
* 由复杂到简单第 5 次改写【最简单的】
*/
def test06() = {
val list = List(1,2,3,Boolean,"Scala" ,3.0D)
// 偏函数的调用:collect
list.collect {
case i: Int => i * 5
}.foreach(println)
}
隐式转换【重要知识点】
1.隐式方法的转换
- 定义方法【套公式】:implicit def 普通类2增强类 (普通类的参数): 增加的类 = new 增加的类(属性)
class Man(val name : String)
class SuperMan (val name : String){
def fly()= {
println(s"$name 会飞")
}
}
object ImplicitApp {
def main(args: Array[String]): Unit = {
implicit def man2SuperMan(man:Man) : SuperMan = new SuperMan(man.name)
// 上面隐式转换后,普通Man具有SuperMan的超能力,能fly()
val man = new Man("张三")
man.fly() // 输出结果:张三 会飞
}
}
假设File中不具备的方法,可以自定义一个RichFile,然后通过隐式转换使File具有自定义RichFile的功能。
class RichFile(val file:File){
def richRead() = Source.fromFile(file.getPath).mkString
}
object ImplicitApp {
def main(args: Array[String]): Unit = {
implicit def file2RichFile(file: File) : RichFile = new RichFile(file)
val file = new File("data/word.md")
println(file.richRead()) // 假设File不具有read功能,通过隐式转换,具有了read功能
}
}
隐式转换封装:import ImplicitAspect._
object ImplicitAspect {
implicit def man2SuperMan(man:Man) : SuperMan = new SuperMan(man.name)
implicit def file2RichFile(file: File) : RichFile = new RichFile(file)
// 去需要隐式转换的界面,引入:import ImplicitAspect._
}
2. 隐式类的转换
- 将implicit 直接定义在class类的前面,就可以直接使用增强类中定义的方法
/**
* @DESC 隐式类的使用,将implicit 直接定义在class类的前面,就可以直接使用增强类中定义的方法
*/
object ImplicitClassApp {
def main(args: Array[String]): Unit = {
println(new File("data/word.md").enhanceRead())
}
implicit class EnhanceFile(file:File){
def enhanceRead() = Source.fromFile(file.getPath).mkString
}
}
3. 隐式参数的转换
def testParam(implicit name:String) = {
println(s"结果:===$name===")
}
def testParamTest() = {
testParam("Scala") // 输出结果:结果:===Scala===
implicit val name:String = "Java" // 参数隐式转换,默认给参数赋值。
// 如果设置了多个implicit的name参数值,就报转换冲突。
testParam // 输出结果:结果:===Java===
testParam("JavaScript")// 输出结果:结果:===JavaScript===
}
隐式参数的转换【需要查找相关作用域】
1) 当前隐式方法的当前作用域
2) 当前A类或者B类任一伴生对象作用域(只能二选一,如果AB都有,会冲突)
- 方法一
// 1)当前隐式方法的当前作用域
class A
class B
def testA2B() = {
implicit def b2A(b:B):A = {
println("====当前b2A方法内的作用域=======")
new A
}
}
def main(args: Array[String]): Unit = {
//在没有进行隐式转换的时候,这样定义val a:A = new B()会报错
val a:A = new B
}
- 方法二
class A
class B
// 2) 当前A类或者B类任一伴生对象作用域(只能二选一,如果AB都有,会冲突)
object A{
implicit def b2A(b:B):A = {
println("====当前A的伴生对象作用域====")
new A
}
}
// object A 和 object B二选一
object B{
implicit def b2A(b:B):A = {
println("====当前B的伴生对象作用域====")
new A
}
}
def main(args: Array[String]): Unit = {
//在没有进行隐式转换的时候,这样定义val a:A = new B()会报错
val a:A = new B
}