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)