开发者学堂课程【Scala 核心编程 - 进阶:上下文界定介绍和应用实例】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/610/detail/9158
上下文界定介绍和应用实例
内容介绍
一、基本介绍
二、上下文界定应用实例
一.基本介绍
与 view bounds 一样 context bounds(上下文界定)也是隐式参数的语法糖。为语法上的方便,引入了"上下文界定”这个概念
二.上下文界定应用实例
要求:使用上下文界定+隐式参数的方式,比较两个Person对象的年龄大小
要求:使用 Ordering 实现比较
ordered 和 ordering 区别:
ordered 是实现继承的一个接口。往往是去重写,或者是实现它的compare方法;
ordering是以继承的方式去写comparator,comparator是个比较器,是通过写外置的对象去实现这个方法。
object ContextBoundsDemo{
implicit val personComparetor=new Ordering Person] {
override def compare(p1:Person,p2:Person):Int=
p1.age-p2.age
}
def main(args:Array[String):Unit={
val p1=new Person(“mary“,30)
val p2=new Person(“smith”,35)
val compareComm4=new CompareComm4(p1p2) printin(compareComm4geatter)
val compareComm5=newCompareComm5(p1p2) printin(compareComm5.geatter)
val compareComm6=new CompareComm6(p1p2) printin(compareComm6.geatter)
//方式1
class CompareComm4[T: Ordering](obj1:T,obj2:T)(implicit comparetor: Ordering[T]){
def geatter=if (comparetor.compare(obj1,obj2)>0)obj1 elseobj2
}
//方式2,将隐式参数放到方法内
class CompareComm5T:Ordering](o1: To2:T){
def geatter={
def f1(implicit cmptor:Ordering[T])=cmptor.compare(o1.o2)
if (f1 > 0) o1 else o2
}}
//方式3,使用implicitly语法糖,最简单(推荐使用)
class CompareComm6T:Orderingl(o1:To2:T{
def geatter={
//这句话就是会发生隐式转换,获取到隐式值personComparetor val comparetor=implicitly[Ordering[T]]
printin"CompareComm6comparetor"+comparetor.hashCode())
if(comparetor.compare(o1,o2)>0)o1 else o2
}}
//一个普通的Person类
class Person(val name: String,val age:Int){
override def toString=this.name +"\t"+ this.age
}
新建一个包:
在里面建一个文件:
package com.atguigu.chapter18.contextbounds
object contextBoundsDemo {
//这里我定义一个隐式值 Ordering [Person]
implicit val personComparetor=new Ordering [Person4] {
override def compare(p1:Person4,p2:Person4):Int=
p1.age-p2.age
}
def main(args: Array[String]): Unit = {
val p1=new Person4(“mary“,30)
val p2=new Person4(“smith”,35)
val compareComm4=new CompareComm4(p1p2) printin(compareComm4geatter)// “smith”,35
//传进去的时候比较器也会被找到,如何知道传进去类型是实现ordering呢?
因为隐式值这个参数里面知道ordering,所以才能用。这时再执行一定会返回斯密斯这个信息。
val compareComm5=new CompareComm5(p1,p2) println(compareComm5.geatter) // "smith", 35
}
}
//一个普通的Person类
class Person4(val name: String, val age: Int) {
//重写toStirng
override def tostring = this.name + "\t"+ this.age
}
//方式1
//说明:
//1.[T:Ordering] 泛型
//2.obj1:T,obj2:T 接受T类型的对象
//3. implicit comparetor: Ordering[t] 是一个隐式参数
class CompareComm4[T: Ordering](obj1:T,obj2:T)(implicit comparetor: Ordering[T]){
def geatter=if (comparetor.compare(obj1,obj2)>0)obj1 elseobj2
}
回忆一下隐式值和隐式参数的定义:
implicit val str1: String ="jack~" //这个就是隐式值
//implicit name: String:name就是隐式参数
如果什么都没有传,那么编译器会在底层直接将隐式值装进去。
其实上面就使用到了隐式值和隐式参数的方法,只是上面的更复杂一点。
下面执行一下:
//方式2,将隐式参数放到方法内
class CompareComm5T:Ordering](o1: To2:T){
def geatter={
def f1(implicit cmptor:Ordering[T])=cmptor.compare(o1.o2) //返回一个数字
//如果f1返回的值>0,就返回o1,否则返回o2
if (f1 > 0) o1 else o2
}
}
这种写法大家要看懂,当你觉得好像很奇怪的时候,只要看到这个东西,一定在上下文能够找到一个隐式值,只是这个隐式值,有可能是直接写在这里,也可能是引进来的,比如在这儿没有写而是用import引进来也是有可能的。这样的写法代码很简单。
下面执行代码:
val compareComm5=new CompareComm5(p1,p2) println(compareComm5.geatter) // "smith", 35
和我们想的是一样的。
//方式3,使用 implicitly 语法糖,最简单(推荐使用)
class CompareComm6T:Orderingl(o1:To2:T{
def geatter={
//这句话就是会发生隐式转换,获取到隐式值personComparetor
//底层仍然使用编译器来完成(绑定赋值)的工作
val comparetor=implicitly[Ordering[T]]
if(comparetor.compare(o1,o2)>0)o1 else o2
}}
运行以下代码:
val compareComm6=new CompareComm6(p1,p2) println(compareComm6.geatter) // "smith", 35
得到:
通过隐式转换拿到的比较器的地址是1018547642。现在要证明它和comparetor是同一个比较器:
直接在主函数里打:println("personComparetor hashcode=" + personComparetor.hashcode())
val compareComm6=new CompareComm6(p1,p2) println(compareComm6.geatter) // "smith", 35
compare 里也有一个用语法糖得到的hashcode。
点击运行:
运行之后可以看到这两个地址是完全一样的。外面的hashcode和得到的hashcode是同一个。其实就是语法糖的作用,它就相当于做一个转换。
有兴趣可以追究一下implicitly的源代码。它的底层是怎么做的呢? personComparetor有一个隐式值过后,在编译的时候直接就把比较器绑定到comparetor上去了,编译器会做会做很多工作。