11_Scala_OOP_03_隐式转换_函数_值_类

举报
alexsully 发表于 2021/05/07 10:45:50 2021/05/07
【摘要】 1 隐式函数 2 隐式值 3 隐式类

隐式函数

隐式转换函数(implicit关键字声明) 的带有单个参数的函数。自动应用,将值从一种类型转换为另一种类型

隐式转换细节
 1 隐式转换与函数名称无关,只与函数签名(函数参数类型和返回值类型)有关
 2  保证在当前作用域下,只有一个隐式函数能被识别->避免冲突
 3  丰富类库功能 例 一个类增加一个方法,可以通过隐式转换来动态增加该功能来实现

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

    //隐式转换函数(implicit关键字声明) 的带有单个参数的函数。自动应用,将值从一种类型转换为另一种类型
    implicit def Impld (d: Double) :Int ={
      d.toInt
    }

    //1 与函数名称无关,只与函数签名(函数参数类型和返回值类型)
    implicit def Implf (f: Float) :Int ={
      f.toInt
    }
    // 2 保证在当前作用域下,只有一个隐式函数能被识别,避免冲突, 此处两个函数签名相同的隐式转换函数, var num: Int = 4.5f 会报错
    implicit def Implf2 (f: Float) :Int ={
      f.toInt
    }

    var num: Int = 4.5f
    var num1: Int = 3.66666666
    println(num + " \t" + num1)
    
    
    // 3 丰富类库功能 例 一个类增加一个方法,可以通过隐式转换来动态增加该功能来实现
    implicit def addBBB(aa: AA) : BB={    // 传入AA  返回BB 对象
    new BB
    }

    val alex = new AA
    alex.BBB_1()  // 隐式转换时机 2 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
    alex.BBB_2()  // 底层:  implicit def addBBB$1(alex).BBB_2     implicit def addBBB(alex) 返回一个 BB 对象

    // 隐式转换时机
    // 1 当方法中的参数的类型与目标类型不一致
    // 2 当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换

    def implict_time(n1: Int){println(" 隐式转换时机")}
    //   implicit def Implf (f: Float) :Int ={
    //      f.toInt
    //    }
    implict_time(20.1f)


class AA {
  def AA(): Unit = { println("AA") }}

class BB {
  def BBB_1(): Unit = { println("BBB_1") }
  def BBB_2(): Unit = { println("BBB_2")}
}

隐式值(隐式变量)   &  优先级
形参变量标记为implicit,编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省(默认)参数 (默认值只能作用在一个形参,隐式值可以作用在多个函数上)

object ImplicitPriority {
  def main(args: Array[String]): Unit = {
    //将形参标记为implicit,编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺省(默认)参数
    implicit var str: String = "Alex "
//    sayHi
    sayHello  // hello  Alex 隐式值优先级大于默认值
    sayHello("Sumi")     //hello  Sumi 实参优先级大于隐式值
  }
  def sayHi(implicit  name: String): Unit = {
    println("hi  " + name)  //hi alex
  }
  
  // 优先级问题 隐式值,默认值,实参
  // 优先级: 实参 >  隐式值 > 默认值
  // 如无 隐式值,仍使用默认值

  def sayHello(implicit  name: String ="Bob"): Unit = {
    println("hello  " + name)
  }
}

隐式类  implicit声明类,同样可以扩展类的功能

object ImplicitClass {
  def main(args: Array[String]): Unit = {
    //1 其所带的构造参数有且只能有一个
    //2 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是 顶级的(top-level  objects) 不能跟包对象平级,无法确定作用域
    //3 隐式类不能是case class
    //4 作用域内不能有与之相同名称的标识符  不能有俩同名的 implicit class Gauss 和 class Gauss


    //implicit声明类,同样可以扩展类的功能
    //Gauss 生成隐式类ImplicitClass.MRS.1 MRS$2(DWS d) main 函数内 有个$2 在作用域内 创建DWS实例 编译器就会让隐式类生效
    //返回一个 ImplicitClass.MRS.1(d) 实例 该实例中有个方法 public void addMRS() { Predef..MODULE$.println("MRS");}
    //  dws.addMRS() 就是调用的  MRS$2(dws).addMRS

    implicit class Gauss(val m : MySQL) {
      def addGaussMethod(): String ={ m + "Gauss"}
      def addGaussInsert(): Unit = {
        println("addGaussInsert")
      }
    }

    implicit class MRS (var d: DWS) {  //ImplicitClass.MRS.1 MRS$2(DWS d)
      def addMRS() {println("MRS")}
    }

    val m1 = new MySQL
    m1.sayOk()  //sayMySQL
    println(m1.addGaussMethod()) //com.chapter09_conversion.MySQL@763d9750Gauss
    m1.addGaussInsert() //addGaussInsert

    val dws = new DWS
    dws.addMRS()   //MRS$2(dws).addMRS
  }
}


class Gauss {}
class MRS {}
class DWS {}
class MySQL {
  def sayOk(): Unit = {println("sayMySQL")}
}

隐式解析机制 (转载)

即编译器是如何查找到缺失信息的,解析具有以下两种规则:
情况1 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象)
情况2 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下

a)  如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索。
b)  如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的伴生对象和String的伴生对象。
c)  如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索。
d)  如果T是个类型注入S#T,那么S和T都会被搜索。



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。