56_隐式转换

/*
* 1. 什么是隐式转换?
* 1. 当编译器第一次编译代码失败时
* 会自动在当前环境中查找能使代码通过编译的方法(通常是数据类型转换)
* 也可以称之为 二次编译
*
* 2. 隐式转换发生在什么时候?
* 1. 发生在编译时期,编译器会自动帮助我们做一些事情
*
* 3. 隐式转换的修饰的位置
* 1. 隐式函数
* 语法 : implicit def f1(参数列表) ...
*
* 2. 隐式类
* 语法 : implicit class objName ...
*
* 要求 : 1. 所带的构造参数 有且只能有一个
* 2. 隐式类必须定义在 类或伴生对象或包对象中
* 即隐式类不能作为 顶级对象
* implicit' modifier cannot be used for top-level objects
*
* 3. 隐式参数
* 语法 : implicit val id:Int = 10 -- 隐式变量
* def f1(implicit str:Int) -- 隐式参数
*
* 4. 隐式解析机制(Scala语法)
* 1. 首先会在当前代码作用域下查找隐式实体(隐式方法、隐式类、隐式对象) (一般是这种情况)
* 2. 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。
* 类型的作用域是指 与该类型相关联的全部伴生对象以及该类型所在包的包对象
* */
-- 1.隐式函数
复制代码
  class MyInt(val self: Int) {
    println("MyInt 对象初始化了")

    def Max(i: Int): Int = if (self >= i) self else i

    def Min(i: Int): Int = if (self >= i) i else self
  }

  object ImplicitFunction extends App {
    // 1.需求 : Int类型的对象,定义比较大小的方法,并返回最大值
    //         13.Max(20) 返回 20

    // 2.思路 : 定义 Int类型的包装类 MyInt,定义Max方法
    //         通过调用 MyInt 来完成需求
    println(s"获取max:${new MyInt(13).Max(20)}")
    println(s"获取max:${new MyInt(21).Max(20)}")

    // 3. 思考 : 每次 完成13.Max(20) 都需要创建 MyInt对象,有没有更简洁的办法呢?
    //               可以定义一个 隐式的转换函数,在每次编译的时候,自动将Int对象 转换成MyInt对象
    implicit def Int2MyInt(i: Int): MyInt = {
      println("隐式函数-Int2MyInt-调用了")
      new MyInt(i)
    }

    println(s"获取max:${13.Max(20)}") 
// 隐式调用 会将13作为参数 去当前作用域下去寻找是否有一个函数 参数类型为Int 返回值类型为MyInt
// 如果找到了 将会自动调用 将13.Max(20) => 隐式函数(13).Max(20)
// 4. 思考 // 1. 隐式函数的编译流程 是怎样的? // 1. 在编译代码时,如果发生编译类型错误,不会立即报错 // 而是根据 参数类型和返回值类型 去当前代码的作用域下 // 寻找有没有 将类型转换的函数,如果找到 则会自动调用 // 2. 注意事项 // 1. 同一作用域下 同一类型(参数类型 + 返回值类型 相同)的隐式函数只能有一个 }
复制代码
-- 2.隐式类
复制代码
  object ImplicitClass extends App {

    //1. 思考 : 在上述需求中,通过隐式函数 完成了 13.Max(20)
    //         但是 一旦离开该作用域(比如其他对象或类中),则需要重新 定义隐式转换函数
    //         有没有方便的方法,不用定义隐式转换函数,就能完成自动类型转换呢?

    //2. 思路 : 可以定义一个 隐式类,通过类的构造器,完成自动类型转换
    implicit class MyInt(val self: Int) {
      println("MyInt 对象初始化了")

      def Max(i: Int): Int = if (self >= i) self else i

      def Min(i: Int): Int = if (self >= i) i else self
    }

    println(s"获取max:${13.Max(20)}") // 隐式调用

    //3. 注意事项
    //   1. 隐式类所带的构造器,有且只能有一个参数
    //   2. 隐式类 必须被定义在 "类"或者"伴生对象"或者"包对象"里
    //         也就是隐式类不能作为顶级类
    //         implicit' modifier cannot be used for top-level objects


  }
复制代码
-- 3.隐式参数
复制代码
  object ImplicitPara extends App {
    //1. 思考 : 调用方法时,不指定参数时,也想有参数传递

    //2. 思路 :
    //      1. 可以使用 默认参数(弊端 :只能在函数定义时,指定参数默认值)
    //      2. 可以使用 隐式参数(可以动态指定实参的值)

    //定义 隐式变量
    implicit var str: String = "大王"
    implicit var str1: Int = 100

    //隐式参数
    def f1(implicit str: String): Unit = println(s"f1方法:${str}")

    def f2(implicit str: String = "小王"): Unit = println(s"f2方法:${str}")

    //方法体内调用 隐式变量
    def f3 = println(s"f2方法:${implicitly[Int]}")

    //调用
    f1
    f1("new")
    f2
    f2("new")
    f3

    //3. 说明
    // 1. 调用流程
    //       通过参数类型 去匹配同作用域下的同类型 隐式变量
    // 2. 注意事项
    //       同作用域下 同类的隐式变量只能定义一个
    //       当定义多个 同类型的隐式变量时, 将造成无法匹配
    // 3. 隐式参数和 默认参数 的优先级 谁高呢?
    //       隐式参数 > 默认参数
  }
复制代码
//隐式解析机制(测试作用域)
/*
* 1. 首先在 当前作用域下查找 符合条件的 隐式变量
* 2. 当前作用域如果没找到
* 会继续在隐式参数的类型的作用域里查找
* 类型的作用域是指 : 与该类型相关联的全部伴生模块
* */
复制代码
  object ImplicitScope extends App with PersonTrait {
    //1. 首先会在当前代码作用域下查找隐式实体
    val teacher = new Teacher()
    teacher.eat()
    teacher.say() //会继续在隐式参数的类型的作用域里查找

    class Teacher {
      def eat(): Unit = println("eat...")
    }

  }

  trait PersonTrait {

  }

  object PersonTrait {

    // 隐式类 : 类型 1 => 类型 2
    implicit class Person5(user: Teacher) {
      def say(): Unit = println("say...")
    }

  }
复制代码

 













posted @   学而不思则罔!  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示