Scala implicit

Scala提供了Java所不具有的隐式转换和隐式参数功能,可以允许你手动指定,将某种类型的对象转换为其他类型的对象。在Spark中有大量的隐式转换和隐式参数。
Scala的隐式转换, 核心是定义隐式转换函数。 定义的隐式转换函数, 只要在编写的程序内引入, 就会被Scala自动使用。
Scala会根据隐式转换函数的签名, 在程序中使用到隐式转换函数接收的参数类型定义的对象时, 会自动将其传入隐式转换函数, 转换为另外一种类型的对象并返回。这就是“隐式转换” 。
隐式转换函数命名随意, 因为通常不会由用户手动调用, 而是由Scala进行调用。 但是如果要使用隐式转换, 则需要对隐式转换函数进行导入。 因此通常建议将隐式转换函数的名称命名为“one2one” 的形式。

隐式转换:
 * 是scala中的一种特殊功能,它能将一种数据类型A转换成另外一种数据类型B,然后数据类型A就可以拥有数据类型B的所有方法,可以看成是对类的一种增强
 * 隐式转换分为两种:
 * 1,隐式转换函数
 * 2,隐式转换值
 * 定义隐式转换的关键字:implicit
 * 隐式转换的命名方式是:one2one


class SpecialPerson(var name: String)
class Older(var name: String)
class Teacher(var name: String)
class Student(var name: String)

object ImplicitDemo01 {
  def buySpecialTic(p: SpecialPerson) = {
    if (p != null) println(p.name + "-购买了一张特殊票") else println("请购买常人票")
  }
  //定义隐式转换函数,将老人、老师转换为特殊人群类
  implicit def any2SpecialPerson(any:Any):SpecialPerson = {
    if(any.isInstanceOf[Older]) {
      val older = any.asInstanceOf[Older]
      new SpecialPerson(older.name)
    }else if (any.isInstanceOf[Teacher]) {
      val teacher = any.asInstanceOf[Teacher]
      new SpecialPerson(teacher.name)
    }else {
      null
    }
  }

  def main(args: Array[String]): Unit = {
    val older = new Older("老人")
    val tc = new Teacher("老师")
    val stu = new Student("学生")
    
    buySpecialTic(older)
    buySpecialTic(tc)
    buySpecialTic(stu)
  }
}

实质是对类的增强!

class RichFile(var file: File) {
  def read() = {
    val context = Source.fromFile(file).mkString
    println(context)
  }
}

object ImplicitDemo02 {
  def main(args: Array[String]): Unit = {
    //将File类转换成RichFile类,以便可以调用RichFile类中的方法,实际上是对File类的增强
    implicit def file2RichFile(file: File): RichFile = new RichFile(file)

    val f1 = new File("C:\\Users\\root\\Desktop\\hello.txt")
    f1.read
  }
}

隐式参数:
   * 在方法中,被implicit修饰的参数,称为隐式参数
   * 隐式参数分为两种:
   * 1,隐式转换函数
   * 2,隐式转换值

class SingPen {
  def write(context: String) = println(context)
}

object ImplicitDemo03 {

  //pen 作为方法的参数,被implicit修饰,成为隐式参数。在调用方法时,该隐式参数可以自动引用。
  def singForExam(name: String)(implicit pen: SingPen) = {
    pen.write(name)
  }

  def main(args: Array[String]): Unit = {
    //声明隐式转换值
    implicit val singPen = new SingPen

    //每个人签到是都要调用singPen,scala会自动调用
    singForExam("张三")
    singForExam("李四")
    singForExam("王五")
  }
}

隐式转换实现二次 排序-ordered & ordering

对象之间进行大小比较,或者排序,需要具备比较大小的功能
具备比较大小的功能有两种方法:
1,继承:继承Comparable接口,实现comparaTo方法,但是这种方法有一定的局限性,这种局限性就是将比较规则写死,后续进行调整,会影响之前的比较
2,隐式转换
可以很好的解决继承带来的局限性,比较规则不写在类中,而是以隐式转换的形式存在

trait Ordered[A] extends Any with java.lang.Comparable[A]  中有用于比较大小的抽象方法   def compare(that: A): Int

trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable 中有用于比较大小的抽象方法  def compare(x: T, y: T): Int

//方法一:继承
class Girl(var name: String, var age: Int, var faceValue: Int) extends Comparable[Girl] {
  override def compareTo(that: Girl): Int = {
    if (this.age - that.age != 0) this.age - that.age
    else if (this.faceValue - that.faceValue != 0) {
      this.faceValue - that.faceValue
    } else this.name.compareTo(that.name)
  }

  override def toString = s"Girl(name=$name,age = $age,faceValue = $faceValue)"
}

//方法二:隐式转换,将比较器放在类外
class Boy(var name: String, var age: Int, var faceValue: Int) {
  override def toString = s"Boy(name=$name,age = $age,faceValue = $faceValue)"
}

//比较器
class Compare[T] {
  //比较方法,第二个参数是隐式转换函数,目的是将T类型转换为Ordered类型,以便可以使用大小比较的方法
  def compareTo(b1: T, b2: T)(implicit x: T => Ordered[T]): T = {
    if (b1 >= b2) b1 else b2
  }
  //比较方法,第二个参数是隐式转换值,目的是将T类型转换为Ordering类型,以便可以使用大小比较的方法
  def compareTo2(b1: T, b2: T)(implicit ord2: Ordering[T]): T = {
    if (ord2.gteq(b1, b2)) b1 else b2
  }

}

object ImplicitDemo04 {
  def main(args: Array[String]): Unit = {
    //隐式转换函数
    implicit def boy2Ordered(b: Boy): Ordered[Boy] = new Ordered[Boy] {
      override def compare(that: Boy): Int = {
        if (b.age - that.age != 0) b.age - that.age
        else if (b.faceValue - that.faceValue != 0) {
          b.faceValue - that.faceValue
        } else b.name.compareTo(that.name)
      }
    }
    val b1 = new Boy("小明", 18, 90)
    val b2 = new Boy("小王", 16, 95)
    val cp1 = new Compare[Boy]
    val resp = cp1.compareTo(b1, b2)
    println(resp)
    
    //隐式转换值
    implicit val ord2: Ordering[Boy] = new Ordering[Boy] {
      def compare(a: Boy, b: Boy): Int = {
        if (a.age - b.age != 0) a.age - b.age
        else if (a.faceValue - b.faceValue != 0) {
          a.faceValue - b.faceValue
        } else a.name.compareTo(b.name)
      }
    }

    val b4 = new Boy("小明", 18, 90)
    val b5 = new Boy("小王", 16, 95)
    val c3 = new Compare[Boy]
    val resB = c3.compareTo2(b4, b5)
    println(resB)

  }
}

扩大隐式转换的作用域

 * 我们可以将隐式转换函数或隐式转换值定义在一个object对象中,来扩大隐式转换的作用域。
 * 以后在其他地方使用的时候,直接import对应的隐式转换函数或隐式转换值
 * 【注意】隐式转换函数或值只能定义在object对象中

object MyPredef {
  implicit def any2SpecialPerson(any: Any): SpecialPerson = {
    if (any.isInstanceOf[Older]) {
      val older = any.asInstanceOf[Older]
      new SpecialPerson(older.name)
    } else if (any.isInstanceOf[Teacher]) {
      val teacher = any.asInstanceOf[Teacher]
      new SpecialPerson(teacher.name)
    } else {
      null
    }
  }

  implicit def file2RichFile(file: File): RichFile = new RichFile(file)

  implicit val singPen = new SingPen

  implicit def boy2Ordered(b: Boy): Ordered[Boy] = new Ordered[Boy] {
    override def compare(that: Boy): Int = {
      if (b.age - that.age != 0) b.age - that.age
      else if (b.faceValue - that.faceValue != 0) {
        b.faceValue - that.faceValue
      } else b.name.compareTo(that.name)
    }
  }

  implicit val ord2: Ordering[Boy] = new Ordering[Boy] {
    def compare(a: Boy, b: Boy): Int = {
      if (a.age - b.age != 0) a.age - b.age
      else if (a.faceValue - b.faceValue != 0) {
        a.faceValue - b.faceValue
      } else a.name.compareTo(b.name)
    }
  }
}

使用时,直接import即可。

import MyPredef.any2SpecialPerson  //直接导入隐式转换函数

class SpecialPerson(var name: String)
class Older(var name: String)
class Teacher(var name: String)
class Student(var name: String)

object ImplicitDemo01 {
  def buySpecialTic(p: SpecialPerson) = {
    if (p != null) println(p.name + "-购买了一张特殊票") else println("请购买常人票")
  }

  def main(args: Array[String]): Unit = {
    val older = new Older("老人")
    val tc = new Teacher("老师")
    val stu = new Student("学生")
    
    buySpecialTic(older)
    buySpecialTic(tc)
    buySpecialTic(stu)
  }
}
import MyPredef.file2RichFile//直接导入对应的隐式转换值

class RichFile(var file: File) {
  def read() = {
    val context = Source.fromFile(file).mkString
    println(context)
  }
}

object ImplicitDemo02 {
  def main(args: Array[String]): Unit = {
    val f1 = new File("C:\\Users\\root\\Desktop\\hello.txt")
    f1.read
  }
}
import MyPredef.singPen //直接导入隐式转换值

class SingPen {
  def write(context: String) = println(context)
}

object ImplicitDemo03 {
  def singForExam(name: String)(implicit pen: SingPen) = {
    pen.write(name)
  }

  def main(args: Array[String]): Unit = {
    //scala会自动调用
    singForExam("张三")
    singForExam("李四")
    singForExam("王五")
  }
}
import MyPredef.ord2
import MyPredef.boy2Ordered

//方法一:继承
class Girl(var name: String, var age: Int, var faceValue: Int) extends Comparable[Girl] {
  override def compareTo(that: Girl): Int = {
    if (this.age - that.age != 0) this.age - that.age
    else if (this.faceValue - that.faceValue != 0) {
      this.faceValue - that.faceValue
    } else this.name.compareTo(that.name)
  }

  override def toString = s"Girl(name=$name,age = $age,faceValue = $faceValue)"
}

//方法二:隐式转换,将比较器放在类外
class Boy(var name: String, var age: Int, var faceValue: Int) {
  override def toString = s"Boy(name=$name,age = $age,faceValue = $faceValue)"
}

//比较器
class Compare[T] {
  //比较方法,第二个参数是隐式转换函数,目的是将T类型转换为Ordered类型,以便可以使用大小比较的方法
  def compareTo(b1: T, b2: T)(implicit x: T => Ordered[T]): T = {
    if (b1 >= b2) b1 else b2
  }
  //比较方法,第二个参数是隐式转换值,目的是将T类型转换为Ordering类型,以便可以使用大小比较的方法
  def compareTo2(b1: T, b2: T)(implicit ord2: Ordering[T]): T = {
    if (ord2.gteq(b1, b2)) b1 else b2
  }

}

object ImplicitDemo04 {
  def main(args: Array[String]): Unit = {

    val b1 = new Boy("小明", 18, 90)
    val b2 = new Boy("小王", 16, 95)
    val cp1 = new Compare[Boy]
    val resp = cp1.compareTo(b1, b2)
    println(resp)

    val b4 = new Boy("小明", 18, 90)
    val b5 = new Boy("小王", 16, 95)
    val c3 = new Compare[Boy]
    val resB = c3.compareTo2(b4, b5)
    println(resB)

  }
}

视图界定

如:T <% Person
T 只能是Person类及其子类,或者T能隐式转换成Person类

class Person05(var name: String) {
  def sayHello = println(s"hello,i am $name")

  def mkFriends(p: Person05) = {
    sayHello
    p.sayHello
  }
}
class Student05(name: String) extends Person05(name)

class Cat(var name: String) {
  def say = println("喵喵喵...")
}
//视图界定:T <% Person,T 只能是Person类及其子类,或者T能隐式转换成Person类
class Party[T <% Person05](p1: T, p2: T) {
  p1.mkFriends(p2)
}

object ImplicitDemo05 {
  def main(args: Array[String]): Unit = {
    //Person05对象
    val p1 = new Person05("张三")
    val p2 = new Person05("李四")
    val pt = new Party[Person05](p1, p2)
    //Student05对象
    val s1 = new Student05("张三")
    val s2 = new Student05("李四")
    val pt2 = new Party[Student05](s1, s2)

    implicit def cat2Person05(c: Cat): Person05 = new Person05(c.name)
    //Cat对象
    val c1 = new Cat("张三")
    val c2 = new Cat("李四")
    val pt3 = new Party[Cat](c1, c2)
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值