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)
}
}
}
}
Scala的隐式转换
最新推荐文章于 2022-05-29 16:53:28 发布