隐式转换函数高级使用

tech2022-07-17  165

Scala隐式转换函数的底层原理

类型不匹配: java:会强制转换 scala:会使用对象的方法进行数据类型转换,隐式转换,scala中只看函数签名(参数列表和返回值) object Scala_List3 { def main(args: Array[String]): Unit = { implicit def f1(d:Double):Int={ d.toInt } implicit def f2(d:Long):Int={ d.toInt } var num:Double = 1 var num1:Int = 3.5 //double=>int var num2:Int = 2001 } } 补充: 隐式转换函数的名字是任意的,隐式转换和函数名无关,和函数签名(参数列表–>返回值)有关。 一个作用域内可以存在多个隐式函数,要保证当前环境能被识别的隐式函数只能有一个,不能有二义性。

隐式转换函数高级使用

需求:类Mysql------>insert 开发完之后发现缺少方法

解决方法:

1.修改源码(重新修改mysql)

2.动态混入(OCP)

3.隐式转换(OCP)

object Scala_List3 { def main(args: Array[String]): Unit = { implicit def addDeletedMethod(mysql: Mysql): DBUtils ={ new DBUtils } var mysql = new Mysql() mysql.insert() mysql.delete() } } class Mysql{ def insert(): Unit = { println("删除数据。。。") } } class DBUtils{ def delete(): Unit = { println("插入数据。。。") } }

隐式转换函数:能帮助我们进行类型转换(隐式:无法直观看到数据类型)。

为什么要引入隐式转换:OCP(开闭原则)

为什么不直接修改源码:在任何一个程序里,类可能存在继承体系,如果直接修改源码的话,可能会给其他的类带来副作用

如果当前对象发现调用的方法不存在,那么会在作用域内进行搜索(隐式转换函数)、查询,看看是否有一个转换后的数据类型存在这个方法。

scala好处:编码简洁 缺点:源码难以理解

隐式值

案例一:

def main(args: Array[String]): Unit = { test1("lizi") //lizi... test1() //huge... test1 //huge... //函数形参用implicit修饰了,调用函数的时候可以不写小括号,默认用的就是隐式函数(形参) def test1(implicit name:String="huge"):Unit={ println(name+"...") } }

案例二:

def main(args: Array[String]): Unit = { implicit var username1:String = "zhou" //隐式参数 //函数形参用implicit修饰了,调用函数的时候可以不写小括号,默认用的就是隐式函数(形参) def test1(implicit name:String="huge"):Unit={ println(name+"...") } def test(implicit name:String="guo"):Unit={ println(name+"...") } test1() //huge test1 //zhou test() //guo test //zhou }

如果当前调用的函数没有用implicit隐式转换关键字,就是调用方法,使用的就是形参

调用函数的时候,虽然使用了隐式转换关键词implicit修饰了形参,调用函数的时候使用了小括号,使用的就是自己的形参;调用函数的时候没有用小括号优先调用隐式参数,注意隐式参数要和形参类型一致,如果没有隐式参数就用自己的形参。

如果调用的函数,没有用implicit隐式转换关键词(关键字),就是调用方法、使用的是形参。

def main(args: Array[String]): Unit = { implicit var username1:String = "zhou" //函数形参用implicit修饰了,调用函数的时候可以不写小括号,默认用的就是隐式函数(形参) def test1(implicit name:String):Unit={ println(name+"...") } test1("hh") //hh... test1 //zhou }

隐式参数注释,test1会报错。

隐式类

案例一:

隐式类(特质、类(混入、继承)):扩展类功能

def main(args: Array[String]): Unit = { var user:User1 = new User1 user.sayHello() user.printInfo() implicit class NewUser(u:User1){//隐式类 def printInfo(): Unit ={ println("打印信息。。。") } } } } class User1{ def sayHello(): Unit ={ println("hello...") }

user1只有sayhello方法,没有其他方法,开发师不可能想的很全面,一定会进行程序的迭代(类:属性、方法修改、增加其他类和特质)

解决方案:1修改源码;2动态混入;3底层增加一个类(研发人员角度)、调用层(用户角度)、添加隐式函数;4用户层添加隐式类

注意:构造函数参数只能有一个;隐式类必须在类、伴生对象、包对象中,不能在顶级类中

补充说明: 隐式转换时机 1)函数中参数 和 调用不一样(触发参数) 2)对象调用的方法在自己的类中不存在(隐式函数、隐式类)

案例二:

def main(args: Array[String]): Unit = { var user: User01 = new User01() user.sayHello() user.printInfo() user.name //隐式类中可以有属性 implicit class NUser(u:User01){ var name : String = "hello world" def printInfo(): Unit ={ println("我在打印信息......") } }//隐式类 } } class User01{ def sayHello(): Unit ={ println("user sayhello ......") } }

案例三:隐式转换复杂操作

隐式转换机制(2种方案): 首先代码的作用域没查找隐式实体(隐式方法、隐式类、隐式对象) 如果第一条检索失败了、会继续查找、隐式参数类型的作用域(object内)开始查找

class A extends B with C(从左向右),常从伴生对象里找

object Scala_List { def main(args: Array[String]): Unit = { var user: User01 = new User01() user.sayHello() user.printInfo() user.name // implicit class Nuser(u:User01){ // var name : String = "hello world" // def printInfo(): Unit ={ // println("我在打印信息......") // } // } } } class User01 extends T1{ def sayHello(): Unit ={ println("user sayhello ......") } } object User01{ implicit class Nuser(u:User01){ var name : String = "hello world" def printInfo(): Unit ={ println("1......") println("我在打印信息......") } } } trait T1{ // implicit class Nuser(u:User01){ // var name : String = "hello world" // def printInfo(): Unit ={ // println("我在打印信息......") // } // }//隐式类 } object T1{ implicit class Nuser(u:User01){ var name : String = "hello world" def printInfo(): Unit ={ println("0......") println("我在打印信息......") } } }

隐式转换最终注意事项

隐式转换前提:1.不能存在二义性 2.不能嵌套使用

def main(args: Array[String]): Unit = { //函数签名相同,出错 implicit def f1(d:Double): Int ={ var num:Int =3.5 d.toInt } implicit def f2(d:Double): Int ={ d.toInt } }

set、map

set不能存储重复元素,不能保留顺序、默认用的是哈希

默认情况下scala使用的是不可变集合,在scala里有可变的也有不可变的set

def main(args: Array[String]): Unit = { //不可变 var set1 = Set(1,2,3) println(set1) //可变 var set2 = mutable.Set(1,2,3) println(set2) }

案例:集合操作------添加数据

def main(args: Array[String]): Unit = { var set1 = Set(1,2,3,"aa")//不可变集合一般没有add这种方法 set1.+=(5) set1+=6 println(set1) //Set(5, 1, 6, 2, 3, aa) var set2 = mutable.Set(1,2,3,"aa")//可变 set2.add(5) set2.+=(6) set2+=8 println(set2) //Set(aa, 1, 5, 2, 6, 3, 8) }

案例:集合操作------删除数据

def main(args: Array[String]): Unit = { var set1 = Set(1,2,3,"aa") val set:Set[Any]=set1.drop(2) println(set) //Set(3, aa) var set2 = mutable.Set(1,2,3,"aa") set2.remove("aa") set2-=(3) println(set2) //Set(1, 2) }

元组基本使用

元组可以理解为一个容器、这个容器可以存放不同的数据类型、可以承载很多元素数据、对数据没有过多的约束。

案例一:元组的基本使用

def main(args: Array[String]): Unit = { //tuple把无关的数据当成一个整体使用,构建元组最多22个值,但可以放list增加数据量 val tuple1:Tuple4[String,Int,String,Boolean] = ("lizi",30,"xianggang",true) val tuple2:(String,Int,String,Boolean) = ("lizi",30,"xianggang",true) val tuple3:Tuple3[String,Int,String] = ("lizi",30,"xianggang") //访问元素 println(tuple3._1) //lizi println(tuple3._2) //30 //遍历 for(elem<-tuple3.productIterator){ println(elem) //lizi 30 xianggang } }

map

案例:scala:可变:无序 | 不可变:有序

def main(args: Array[String]): Unit = { //有序 var map1 = Map("jiangjingwen"->40,"zhangting"->20,"linruiyang"->30) println(map1) //Map(jiangjingwen -> 40, zhangting -> 20, linruiyang -> 30) //无序 var map2 = mutable.Map("jiangjingwen"->40,"zhangting"->20,"linruiyang"->30) println(map2) //Map(linruiyang -> 30, jiangjingwen -> 40, zhangting -> 20) } def main(args: Array[String]): Unit = { var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) println(map("B")) //2 //println(map("E")) //java里访问不存在的key会返回null,scala里访问不存在的key会报错 //mutable.Map[String,Int] //构建一个空的map }

案例:Map 增删改查

def f2(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) if (map.contains("E")){ println("执行存在逻辑") }else{ println("执行不存在逻辑") } } def f3(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) println(map.get("A"))//存在:Some println(map.get("R"))//不存在:None } def f4(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) println(map.getOrElse("A","默认值"))//如存在返回value值,不存在返回默认值 1 println(map.getOrElse("X","默认值")) //默认值 } def f5(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) map += ("F"->7) //key不存在增加键值对 Map(D -> 4, A -> 1, C -> 3, F -> 7, B -> 2) println(map) map += ("C"->7) //key存在会覆盖 Map(D -> 4, A -> 1, C -> 7, F -> 7, B -> 2) println(map) } def f6(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) var map2=map + ("G"->1,"H"->2) //返回的是新的对象 println(map) //Map(D -> 4, A -> 1, C -> 3, B -> 2) println(map2) //Map(D -> 4, G -> 1, A -> 1, C -> 3, H -> 2, B -> 2) map += ("GG"->1,"HH"->2) println(map) //Map(D -> 4, GG -> 1, A -> 1, C -> 3, HH -> 2, B -> 2) } def f7(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) map -= ("A","B") println(map) //Map(D -> 4, C -> 3) } def f8(): Unit ={ var map:mutable.Map[String,Int] = mutable.Map(("A",1),("B",2),("C",3),("D",4)) //map.foreach(print) for(v<-map){ //java编程套路 println(v+" ") } for((k,v)<-map){ println(k+" "+v) } for (v<-map.keys){ map.values } }

集合常用函数

集合基本方法

var list = List(1,2,3,4) //求和 println("sum = "+list.sum) //求最大值 println("max = "+list.max) //求最小值 println("min = "+list.min) //求乘积 println("product = "+list.product) //反转 println("reverse = "+list.reverse)

高阶出阶玩法

1.了解每个高阶函数功能

补充:确定的内容底层封装了(封装:什么内容需要底层实现,什么内容提交给用户实现),底层不确定的(行为参数化)

2.每个高级函数变化的东西是什么(需要用户层给高阶函数传递什么规则,才能让当前的高阶函数正常的执行)

高阶函数需要的函数(规则)----》输入的一般是当前集合的每个元素,但是返回值要特殊记忆一下

def f2(): Unit ={ var list = List(1,2,3,4) val inttoints:Map[Int,List[Int]] = list.groupBy(t=>t) inttoints.foreach(t=>print(t._1+"--"+t._2+":")) //2--List(2):4--List(4):1--List(1):3--List(3): }

按首字母分组:

def f2(): Unit ={ var list:List[String] = List("11","12","33","34") val chartostr:Map[Char,List[String]] = list.groupBy(e=>e.charAt(0)) val strtostr:Map[String,List[String]] = list.groupBy(e=>e.substring(0,1)) chartostr.foreach(t=>print(t._1+"--"+t._2))//1--List(11, 12)3--List(33, 34) strtostr.foreach(t=>print(t._1+"--"+t._2))//1--List(11, 12)3--List(33, 34) }

按奇偶数分组

def f2(): Unit ={ var list:List[Int] = List(1,2,3,4) val booleantoInT:Map[Boolean,List[Int]]=list.groupBy(i=>i%2==0) booleantoInT.foreach(t=>print(t._1+"--"+t._2)) //false--List(1, 3)true--List(2, 4) }

sortWith高阶函数(指定规则排序):

def f2(): Unit ={ var list:List[Int] = List(5,6,1,2,3,4) //输入什么就按照什么排序 var ints:List[Int] = list.sortBy(x=>x) println(ints.mkString("|"))//1|2|3|4|5|6 println(ints.reverse.mkString("|"))//6|5|4|3|2|1 //列表排序的:需要传递函数,输入列表中两个数值然后比较规则 //输入的形参的两个值,左边小于右边是升序,左边大于右边是降序 println(list.sortWith((x,y)=>x<y).mkString(","))//1,2,3,4,5,6 //首字母排序 var list1:List[String] = List("11","32","23","24") println(list1.sortWith((x,y)=>x.charAt(0)<y.charAt(0)).mkString(","))//11,23,24,32 //查看中间过程 list1.sortWith((x,y)=>{ print(x+" "+y) x.charAt(0)<y.charAt(0) }) //list迭代 for(elem<-list.iterator){ println(elem)//11322324 } }

简易版本wordcount:

def f2(): Unit ={ var list:List[Int] = List(1,2,3,4,4) var tuples:List[(Int,Int)] = list.map(x=>(x,1)) //(1,1)|(2,1)|(3,1)|(4,1)|(4,1) println(tuples.mkString("|")) val intTotuples: Map[Int, List[(Int, Int)]] = tuples.groupBy(x=>x._1) println(intTotuples.mkString("|")) //2 -> List((2,1))|4 -> List((4,1), (4,1))|1 -> List((1,1))|3 -> List((3,1)) //统计次数 val intoint: Map[Int, Int]= intTotuples.map(t=>(t._1,t._2.size)) println(intoint.mkString("|"))//2 -> 1|4 -> 2|1 -> 1|3 -> 1 }

单词出现次数最多的前3

def f2(): Unit ={ var wordList = List("hello","xuchun","hello","hello","jinboran", "sunyun","nini","jinboran","linyun","zhaoliyin","nini") //按单词分组 val groupbyRDD: Map[String, List[String]] = wordList.groupBy(word=>word) //单词计数 val mapRDD: Map[String, Int] = groupbyRDD.map(t=>(t._1,t._2.size)) println(mapRDD.mkString("|")) val sortRDD:List[(String, Int)] = mapRDD.toList.sortWith((x,y)=>x._2>y._2) println(sortRDD.mkString("|")) val result: List[(String, Int)] = sortRDD.take(3) println(result.mkString("|")) }

flatmap / fliter / zip 等函数的使用

def f1(): Unit ={ //flatmap map关系 var wordlist: List[String] = List("hello guanx","hello guant","hello guanz") //扁平化(数组里的值作为泛型) val faltMap: List[String] = wordlist.flatMap(x=>x.split(" ")) val groupbyRDD: Map[String, List[String]] =faltMap.groupBy(word=>word) groupbyRDD.map(t=>(t._1,t._2.size)) // println(faltMap.mkString("|")) //hello|guanx|hello|guant|hello|guanz // val str: List[Array[String]] = wordlist.map(x=>x.split(" ")) // println(str.mkString("|")) //[Ljava.lang.String;@880ec60|[Ljava.lang.String;@3f3afe78|[Ljava.lang.String;@7f63425a } def f3(): Unit ={ val list = List(1,2,3,4) val filterRDD: List[Int] = list.filter(x => false) filterRDD.foreach(t=>print(t))//没有输出 val filterRDD1: List[Int] = list.filter(x => true) filterRDD1.foreach(t=>print(t))//1234 } def f4(): Unit ={ val list1 = List(1, 2, 3) val list2 = List(4, 5, 6,7) val tuple: List[(Int,Int)]=list1.zip(list2)//对位匹配 print(tuple.mkString("|")) //(1,4)|(2,5)|(3,6) } def f5(): Unit ={ val list1 = List(1, 2, 3) val list2 = List(1, 2, 4) val ints: List[Int] = list1.union(list2) //合并 val ints1: List[Int] = list1.intersect(list2) //交集 val ints2: List[Int] = list1.diff(list2)//差集 print(ints.mkString("|"))//1|2|3|1|2|4 print(ints1.mkString("|"))//1|2 print(ints2.mkString("|"))//3 }

WordCount加强版:

def f6(): Unit ={ //hello 14 world 7 var linelist: List[(String, Int)] = List(("hello scala hello world",4), ("hello world",3),("hello hadoop",2),("hello hbase",1)) val flatmapRDD: List[(String,Int)] = linelist.flatMap(t=>{ var line:String = t._1 //"hello scala hello world" val word: Array[String] = line.split(" ") //"hello" "scala" "hello" "world" val mapRDD: Array[(String, Int)] = word.map(w=>(w,t._2)) //("hello",4),("scala",4).... mapRDD }) val groupRDD: Map[String, List[(String, Int)]] = flatmapRDD.groupBy(t=>t._1) val finalRDD: Map[String, Int] = groupRDD.map(t=>{ val countlist: List[Int] = t._2.map(tt => tt._2)//List(4,3) (t._1,countlist.sum) }) finalRDD.foreach(println) }

输出: (world,7) (hadoop,2) (scala,4) (hello,14) (hbase,1)

最新回复(0)