Scala的隐式转换

import java.io.Serializable

import scala.annotation.elidable
import scala.beans.BeanProperty
import scala.collection.immutable.HashMap
import scala.collection.mutable
import scala.reflect.ClassTag

/**
  * keyPoint
  * xx  08/07/25 09:00
  */
class ControlProgrammer extends FreeSpec {

  "隐式转换:把一种类型自动转换到另一种类型" - {

    /*
     * 只有标记为implicit的变量,函数或对象定义才能被编译器当做隐式操作目标。
     * implicit关键字只能用来修饰方法、变量(参数)和伴随对象。
     * 隐式转换的方法(变量和伴随对象)在当前范围内才有效。如果隐式转换不在当前范围内定义(比如定义在另一个类中或包含在某个对象中),那么必须通过import语句将其导入
     */
    "隐式视图" - {

      "隐式值,隐式参数" in {

        class Demo {
          // name为隐式参数, 隐式参数当不传值时, 传入自己定义的隐式值
          def person(implicit name: String) = name

          // 定义隐式值
          implicit val p = "Person"

          // 此处因为调用person方法没有传参数, 所以传入了隐式值 Person
          val ps = person
          println(ps)

        }
        new Demo

      }

      "隐式方法: 使用隐式方法可以调用类中本不存在的方法,本质上把不存在该方法的类隐式转换成了存在该方法的类,然后进行调用" - {

        "通过定义隐式方法使用隐式转换的特性,类调用自己不存在的方法" in {
          // 定义Demo类, 有方法method
          class Demo {
            def method(s: String) = println("后海有树的" + s)
          }

          // 定义隐式转换, 编译器会在指定情况下把Test对象转换称Demo
          implicit def testToDemo(demo: Test) = new Demo

          // 定义Test类,它不存在method方法
          class Test {

            // 通过隐式转换,test对象调用到了Demo类的method方法
            val test = new Test
            test.method("院子")

          }
        }

        "隐式函数转换优先级" in {

          // Scala编译器优先选择了方法的参数作为转换对象,而没有选择调用方法的对象!
          class LineNumber(val num: Int) {
            def +(that: LineNumber) = new LineNumber(this.num + that.num)
          }

          val lineNumOfPage1 = new LineNumber(112)
          val lineNumOfPage2 = new LineNumber(120)

          println(lineNumOfPage1 + lineNumOfPage2) // 理所应当的返回了一个LineNumber对象

          // 如果我想使用 1 + lineNumOfPage1 或者 lineNumOfPage1 + 1, 这时我们需要定义隐式转换
          object LineNumber {

            implicit def intToLineNumber(i: Int) = new LineNumber(i)

            implicit def lineNumberToInt(o: LineNumber) = o.num

          }

          // 理论上来说,在定义了隐式转换后,都会把Int值2转换成LineNumber对象进行+
          val num1 = lineNumOfPage1.+(2) // lineNumOfPage1.+(LineNumber.intToLineNumber(2));
          val num2 = 2 + lineNumOfPage2 // 2.+(LineNumber.lineNumberToInt(lineNumOfPage2));

          /*
           * 这是我们发现,num1的结果是LineNumber对象,而num2是Int值,这里就出现了隐式转换优先级的问题:
           * 默认Scala编译器优先选择了方法的参数作为转换对象,而没有选择调用方法的对象
           * 通过打印class类型, 发现num1是LineNumber对象类型,num2是Int类型
           */
          s"num1: ${num1.num}, and class is: ${num1.getClass}".show() // num1: com.dreamponline.scala_train.keypoint.ControlProgrammer$2@4b168fa9
          s"num1: $num2, and class is: ${num2.getClass}".show() // num2: 122


          // 第二种优先级转换

          // 定义两个隐式转换,分别是any -> String, int -> String
          object Conversion {

            implicit def anyToString(x: Any) = {
              println("调用Any=>String方法")
              x.toString
            }

            implicit def intToString(x: Int) = {
              println("调用Int=>String方法")
              x.toString
            }

          }

          // 当我们调用1.endsWith("2")时,发现调用的是intToString隐式转换方法,这就说明了在能确定类型的情况下,编译器会默认选择已经确定了类型的隐式转换方法
          import Conversion._
          val bool = 1.endsWith("1") // 调用Int=>String方法   false
          println(bool)

        }

      }

      "隐式类: 对比隐式方法不需要创建类的实例,然后去使用隐式转换" in {

        /*
         * 1.其所带的构造参数有且只能有一个
         * 2.隐式类必须被定义在类,伴生对象和包对象里
         * 3.隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾)
         * 4.作用域内不能有与之相同名称的标示符
         */

        // 隐式类定义
        implicit class Demo(x: Int) {
          def add(y: Int) = x + y
        }

        // 隐式调用
        val a = 1.add(2) // Demo(1).add(2)
        println(a)

      }

    }

  }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值