目录

隐式(implicit)详解

隐式参数

 隐式的转换类型

隐式类

泛型

上界(UpperBounds)/下界(lowerbounds)

视图界定(view bounds)/上下文界定(Context bounds )

比较


隐式(implicit)详解


掌握 implicit 的用法是阅读 spark 源码的基础,也是学习 Scala 其它的开源框架的关键, implicit 可分为:

  1. 隐式参数
  2. 隐式转换类型
  3. 隐式类

隐式参数


定义方法时,可以把参数列表标记为 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))
 


当调用包含隐式参数的方法时,

  1. 如果当前上下文中有合适的隐式值,则编译器会自动为该组参数填充合适的值,且上下文中只能有一个符合预期的隐式值。
  2. 如果没有编译器会抛出异常。当然,标记为隐式参数的我们也可以手动为该参数添加默认值。

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

当函数和方法同时存在时,先是函数再是方法

方法及函数定义:

 Scala高级语法_scala比较

入门案列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.age

    override 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());
        }
    }
}