(八)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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值