Scala 高阶(十一):隐式转换和泛型
原创
©著作权归作者所有:来自51CTO博客作者百思不得小赵的原创作品,请联系作者获取转载授权,否则将追究法律责任
大家好,我是百思不得小赵。
创作时间:2022 年 8 月 8 日
博客主页: 🔍点此进入博客主页 —— 新时代的农民工 🙊
—— 换一种思维逻辑去看待这个世界 👀
目录
在Scala中有一种特殊的机制,当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译。
一、隐式转换
- 隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。
隐式函数
- 函数定义前加上
implicit
声明为隐式转换函数。 - 当编译错误时,编译器会尝试在当前作用域范围查找能调用对应功能的转换规则,这个过程由编译器完成,称之为隐式转换或者自动转换。
implicit def convert(num: Int):MyRichInt = new MyRichInt(num)
举个栗子:
object Test_Implicit {
def main(args: Array[String]): Unit = {
// 隐式函数
implicit def convert(num: Int):MyRichInt = new MyRichInt(num)
println(12.myMax(16))
}
}
// 自定义类
class MyRichInt(val self: Int) {
// 自定义比较大小的方法
def myMax(n: Int): Int = if (n < self) self else n
def myMain(n: Int): Int = if (n < self) n else self
}
隐式参数
普通方法或者函数中的参数可以通过 implicit
关键字声明为隐式参数,调用该方法时,就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。
说明:
- 同一个作用域中,相同类型的隐式值只能有一个
- 编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。
- 隐式参数优先于默认参数
举个栗子:
implicit val str: String = "alice"
implicit val num: Int = 12
def sayHello(implicit name: String) :Unit={
println(" hello, " + name)
}
sayHello
// 简便写法
def hiAge(): Unit={
println("hi, " + implicitly[Int])
}
hiAge()
隐式类
在 Scala2.10
后提供了隐式类,可以使用 implicit
声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。
说明:
- 隐式类所带的构造参数有且只能有一个
- 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。
举个栗子:
// 隐式类
implicit class MyRichInt2(val self: Int) {
// 自定义比较大小的方法
def myMax2(n: Int): Int = if (n < self) self else n
def myMain2(n: Int): Int = if (n < self) n else self
}
println(12.myMax2(16))
隐式机制
作用域:
- 首先在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)。
- 如果第一条规查找隐式对象失败,会继续在隐式参数的类型的作用域中查找。
- 类型的作用域是指该类型相关联的全部伴生对象以及该类型所在包的包对象。
说明:
- 隐式函数和隐式类可以用于扩充类的功能,常用语比如内建类Int Double String这种。
- 隐式参数相当于就是一种更高优先级的默认参数。用于多个函数需要同一个默认参数时,就不用每个函数定义时都写一次默认值了。
二、泛型
-
[TypeList],
定义和使用都是。 - 常用于集合类型中用于支持不同元素类型。
- 和java一样通过类型擦除/擦拭法来实现。
- 定义时可以用
+-
表示协变和逆变,不加则是不变。
协变和逆变
语法:
class MyList[+T]{ } //协变
class MyList[-T]{ } //逆变
class MyList[T] //不变
举个栗子:
object Test_Generics {
def main(args: Array[String]): Unit = {
// 协变和逆变
val child: Parent = new Child
val childList: MyCollection[Parent] =new MyCollection[Child]
// val childList1: MyCollection[SubChild] =new MyCollection[Child]
}
}
class Parent{}
class Child extends Parent{}
class SubChild extends Child{}
// 定义带泛型的集合类型
class MyCollection[+E] {}
说明:
比如Son
和Father
是父子关系,Son
是子类。
- 协变
(Covariance)
:MyList[Son]是MyList[Father]的子类,协同变化。 - 逆变
(Contravariance)
:MyList[Son]是MyList[Father]的父类,逆向变化。 - 不变
(Invariant)
:MyList[Father] MyList[Son]没有父子关系。
泛型上下限
- 泛型上限:class MyList[T <: Type],可以传入Type自身或者子类。
- 泛型下限:class MyList[T >: Type],可以传入Type自身或者父类。
举个栗子:
object Test03_Generics {
def main(args: Array[String]): Unit = {
// 上下限
def test[A <:Child](a: A)={
println(a.getClass.getName)
}
test[Child](new Child)
test[SubChild](new SubChild)
test[Child](new SubChild)
}
}
class Parent{}
class Child extends Parent{}
class SubChild extends Child{}
// 定义带泛型的集合类型
class MyCollection[+E] {}
本次分享的内容到这里就结束了,整个Scala专栏的总结也随之告一段路,希望对大家学习Scala有所帮助!!