目录
上界(UpperBounds)/下界(lowerbounds)
视图界定(view bounds)/上下文界定(Context bounds )
隐式(implicit)详解
掌握 implicit 的用法是阅读 spark 源码的基础,也是学习 Scala 其它的开源框架的关键, implicit 可分为:
- 隐式参数
- 隐式转换类型
- 隐式类
隐式参数
定义方法时,可以把参数列表标记为 implicit,表示该参数是隐式参数。
一个方法只会有一 个隐式参数列表,置于方法的最后一个参数列表。
def add(a: Int)(implicit b: Int) = a + b
//方法的参数如果有多个隐式参数的话,只需要使用一个implicit关键字即可,隐式参数列表必须放在方法的参数列表后面
def addPlus(a: Int)(implicit b: Int, c: Int) = a + b + c
println(add(5))
println("===== "+addPlus(5))
当调用包含隐式参数的方法时,
- 如果当前上下文中有合适的隐式值,则编译器会自动为该组参数填充合适的值,且上下文中只能有一个符合预期的隐式值。
- 如果没有编译器会抛出异常。当然,标记为隐式参数的我们也可以手动为该参数添加默认值。
implicit val content = 1
def say(implicit content: String = "明天放假拉") = println(content)
say("下午好")
//say方法的参数是隐式参数,如果你没有传递参数的话,编译器在编译的时候会自动的从当前的上下文中找一个隐式值(符合参数的类型的隐式值)
say
// 编译器在查找隐式值的时候,不能有歧义,下面两句话只可以存在一个
// implicit val msg = "你好帅"
implicit val msg1 = "你好帅。。。。"
隐式的转换类型
使用隐式转换将变量转换成预期的类型是编译器最先使用 implicit 的地方。
当编译器看到类 型 X 而却需要类型 Y,它就在当前作用域查找是否定义了从类型 X 到类型 Y 的隐式定义。
入门案列1:将double转换成int
// 定义一个隐式的方法
implicit def double2Int(double: Double) = {
println("---double2Int---")
double.toInt
}//函数
implicit val fdouble2Int = (double: Double) => {
println("---fdouble2Int---")
double.toInt
}println("-------------隐式类型转换---------")
// age是一个Int类型,但是赋值的时候却是一个浮点型,此刻编译器会在当前上下文中找一个隐式转换,找一个能把浮点型变成Int的隐式转换
val age: Int = 20.5
println(age) //20当函数和方法同时存在时,先是函数再是方法
方法及函数定义:
入门案列2:写一个方法返回文件行数
// 返回文件的记录行数
class RichFile(file: File) {
def count(): Int = {
val fileReader = new FileReader(file)
val bufferedReader = new BufferedReader(fileReader)
var sum = 0
try {
var line = bufferedReader.readLine()
while (line != null) {
sum += 1
line = bufferedReader.readLine()
}
} catch {
case _: Exception => sum
} finally {
fileReader.close()
bufferedReader.close()
}
sum
}}
// 定义了一个隐式方法,将file类型变成RichFile
implicit def file2RichFile(file: File) = new RichFile(file)
val file = new File("D:\\a.txt")
println("Count = "+file.count())
隐式类
入门案列2:给file添加一个read方法
泛型// 隐式类 - 只能在静态对象中使用,在 隐式类加了一个read方法
implicit class FileRead(file: File) {def read = Source.fromFile(file).mkString // scala里面有一个读文件内容的方法
}
val file = new File("D:\\a.txt")
println(s"FileContent = ${file.read}")
通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型。我们不可能一一列举所 有的参数类型重载函数。
那么程序引入了一个称之为泛型的东西,这个类型可以代表任意的数据类型。
入门案列1:
在 S c a l a 定 义 泛 型 用 [ C ] ,中间的字母‘’C‘’什么都可以
abstract class Message[C](content: C)
/ / 子 类 扩 展 的 时 候 , 约 定 了 具 体 的 类 型
class StrMessage(content: String) extends Message(content)
class IntMessage[Int](content: Int) extends Message[Int](content)
入门案列2:
// 定义一个泛型类衣服
class Clothes[A, B, C](val clothType: A, val color: B, val size: C)
// 枚举类
object ClothesEnum extends Enumeration {
type ClothesEnum = Value
val 上衣, 内衣, 裤子 = Value}
object ScalaFanXing {
def main(args: Array[String]): Unit = {
val clth1 = new Clothes[ClothesEnum, String, Int](ClothesEnum.上衣, "black", 150)
println(clth1.clothType)
val clth2 = new Clothes[ClothesEnum, String, String](ClothesEnum.上衣, "black", "M")
println(clth2.size)}
}
上界(UpperBounds)/下界(lowerbounds)
不会发生隐式转换,除非用户显示的指定,
上界:
java中的 <T extends Comparable>, <? extends Comparable>
Scala 的写法为: [T<:Test] [_<:Test]
下界:
java: <T super Test> <? super Test>
scala : [T>:Test] [_>:Test]
入门案列:比较两个数值大小。T实现Comparable接口
class CmpComm[T <: Comparable[T]](o1: T, o2: T) {
def bigger = if(o1.compareTo(o2) > 0) o1 else o2
}val cmpcom = new CmpComm(1, 2) //报错 ,int类型没有实现Comparable,所以报错
val cmpcom = new CmpComm[Integer](1, 2) //我们显示的调用了int隐式转换为integer,所以不报错
println(cmpcom.bigger)
视图界定(view bounds)/上下文界定(Context bounds )
视界比<:适用的范围更广,除了所有的子类型,还允许隐式转换过去的类型。
<% 除了方法使用之外,class 声明类型参数时也可使用: class A[T<%Int]
入门案列1:比较数字大小
class CmpComm[T <% Comparable[T]](o1: T, o2: T) {
def bigger = if(o1.compareTo(o2) > 0) o1 else o2
}val cmpcom = new CmpComm(1, 2)
println(cmpcom.bigger) // 不会报错,<% 会允许隐式转换
入门案列2:比较对象大小,没有用视图界定的隐士转换
class Students(val name: String, val age: Int) extends Ordered[Students]{
override def compare(that: Students): Int = this.age - that.ageoverride def toString: String = this.name + "\t" + this.age
}class Students(val name: String, val age: Int) {
override def toString: String = this.name + "\t" + this.age
}
val tom = new Students("Tom", 18)
val jim = new Students("Jim", 20)
val cmpcom = new CmpComm(tom, jim)println(cmpcom.bigger)、
这儿调用的cmpcom以下几种比较大小都可以
上届界定:
class CmpComm[T <: Comparable[T]](o1: T, o2: T) {
def bigger = if(o1.compareTo(o2) > 0) o1 else o2
}视图界定:
class CmpComm[T <% Comparable[T]](o1: T, o2: T) {
def bigger = if(o1.compareTo(o2) > 0) o1 else o2
}
入门案列3:比较对象大小,使用视图界定的隐士转换
视图界定:
class CmpComm[T <% Ordered[T]](o1: T, o2: T) {
def bigger = if(o1 > o2) o1 else o2
}因为类没有实现 ,所以需要使用隐士方法把T转换为Ordered[T]
// 隐式将Student -> Ordered[Student]
implicit def student2OrderedStu(stu: Students) = new Ordered[Students]{
override def compare(that: Students): Int = stu.age - that.age
}
// class Students(没有实现Comparable
class Students(val name: String, val age: Int) {
override def toString: String = this.name + "\t" + this.age
}val tom = new Students("Tom", 18)
val jim = new Students("Jim", 20)
val cmpcom = new CmpComm(tom, jim)println(cmpcom.bigger);
Context bounds 上下文界定
与 viewbounds 一样 contextbounds(上下文界定)也是隐式参数的语法糖。也会发生隐士转换
入门案列1:
传递比较器,定义了一个隐士的比较器当做参数传递,所以现在缺一个比较器
class CmpComm[T: Ordering](o1: T, o2: T)(implicit cmptor: Ordering[T]) {
def bigger = if (cmptor.compare(o1, o2) > 0) o1 else o2
}
// 比较器:一个隐式对象实例 -> 一个又具体实现的Comparator
implicit val comparatorStu = new Ordering[Students] {
override def compare(x: Students, y: Students): Int = x.age - y.age
}class Students(val name: String, val age: Int) {
override def toString: String = this.name + "\t" + this.age
}
val tom = new Students("Tom", 18)
val jim = new Students("Jim", 20)
val cmpcom = new CmpComm(tom, jim)println(cmpcom.bigger);
入门案列2:
class CmpComm[T: Ordering](o1: T, o2: T) {
def bigger = {
def inner(implicit cmptor: Ordering[T]) = cmptor.compare(o1, o2)
if (inner > 0) o1 else o2
}
}// 比较器:一个隐式对象实例 -> 一个又具体实现的Comparator
implicit val comparatorStu = new Ordering[Students] {
override def compare(x: Students, y: Students): Int = x.age - y.age
}class Students(val name: String, val age: Int) {
override def toString: String = this.name + "\t" + this.age
}
val tom = new Students("Tom", 18)
val jim = new Students("Jim", 20)
val cmpcom = new CmpComm(tom, jim)println(cmpcom.bigger);
入门案列3:
比较class CmpComm[T: Ordering](o1: T, o2: T) {
def bigger = {
val cmptor = implicitly[Ordering[T]]
if(cmptor.compare(o1, o2) > 0) o1 else o2
}
}// 比较器:一个隐式对象实例 -> 一个又具体实现的Comparator
implicit val comparatorStu = new Ordering[Students] {
override def compare(x: Students, y: Students): Int = x.age - y.age
}class Students(val name: String, val age: Int) {
override def toString: String = this.name + "\t" + this.age
}
val tom = new Students("Tom", 18)
val jim = new Students("Jim", 20)
val cmpcom = new CmpComm(tom, jim)println(cmpcom.bigger);
在Scala中对应Comparable的是Ordered这个特质,Comparator 对应 Ordering
实现Comparable重写compareTo方法,this.faceValue - o.faceValue;
Comparator 对应 Ordering,重写了compare方法,o1.getFaceValue() - o2.getFaceValue()
第一种:Comparator重写了compare方法,o1.getFaceValue() - o2.getFaceValue()
public class Teachers {
private String name;
private int faceValue;public Teachers(String name, int faceValue) {
this.name = name;
this.faceValue = faceValue;
}
}
public class Appcmp {
public static void main(String[] args) {
Teachers dd = new Teachers("丁丁", 99);
Teachers jj = new Teachers("静静", 100);List<Teachers> list = new ArrayList<Teachers>();
list.add(dd);
list.add(jj);
// 比较2个老师的颜值 --- 比较器
Collections.sort(list, new Comparator<Teachers>() {
@Override
public int compare(Teachers o1, Teachers o2) {
return - (o1.getFaceValue() - o2.getFaceValue());
}
});for (Teachers teachers : list) {
System.out.println("teachers = " + teachers.getName());
}
}
}
第二种:实现Comparable重写compareTo方法,this.faceValue - o.faceValue;
public class Teachers implements Comparable<Teachers> {
private String name;
private int faceValue;public Teachers(String name, int faceValue) {
this.name = name;
this.faceValue = faceValue;
}@Override
public int compareTo(Teachers o) {
return this.faceValue - o.faceValue;
}
}
public class Appcmp {
public static void main(String[] args) {
Teachers dd = new Teachers("丁丁", 99);
Teachers jj = new Teachers("静静", 100);List<Teachers> list = new ArrayList<Teachers>();
list.add(dd);
list.add(jj);
Collections.sort(list);for (Teachers teachers : list) {
System.out.println("teachers = " + teachers.getName());
}
}
}