Scala编程语言中引入了一种叫做隐式类的新特性。隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。隐式转换是一项强大的程序语言功能,它不仅能够简化程序设计,也能够使程序具有很强的灵活性。掌握Scala语言隐式转换,了解其隐式转换的作用与原理是很有必要的,否则很难得以应手地处理日常开发中的问题。
在Scala编程语言中,隐式转换到处存在,只不过scala语言为我们隐藏了相应的细节。例如scala中的类继承层次结构中,就存在固有的隐式转换。
在没有定义隐式转换前,下列赋值的话会报错:
添加隐式转换函数后可以实现Double类型到Int类型的赋值,示例:
/**
* 定义了一个从Double类型转换到Int类型的隐式转换方法
*/
implicit def doubleToInt(value: Double): Int = {
println("implicitconversion double to int");
value.toInt
}
def main(args: Array[String]): Unit = {
valx: Int = 9.6
println(x)
}
输出结果:
implicitconversion double to int
9
/**
* 隐式类的运作方式:
* 隐式类的主构造函数只能有一个参数(有两个以上并不会报错,但是这个隐式类永远不会被编译器作为隐式类在隐式转化中使用)
* 且这个参数的类型就是将要被转换的目标类型
* 隐式转换类将包裹目标类型,隐式类的所有方法都会自动"附加"到目标类型上
*
* @param origin 隐式类构造函数参数
*/
implicit class OperateAdd(origin: Int) {
def add(value: Int): Int = {
origin + value;
}
}
def main(args: Array[String]): Unit = {
val sum = 5.add(6);
println(s"5+6=${sum}")
}
输出结果:
5+6=11
隐式类有如下几个限制:
1、只能在另一个trait/类/对象的内部定义;
2、构造函数只能携带一个非隐式参数;
3、在同一作用域内,不能有任何方法、成员或对象与隐式类同名;
3.1 隐式转换的发生
在什么时候会发生隐式转换呢,主要有一下几种情况。
(1)当方法中的参数类型与实际类型不一致时,会发生隐式转换。
implicit def toInt(value: Int): Int = {
value.toInt
}
toInt(9.6)
(2)当调用类中不存在的方法或成员时,会自动将对象进行隐式转换。
class Person(varname: String) {}
class PersonWorker(person: Person) {
def work = {
println(s"I am ${person.name},I amprogrammer.")
}
}
def main(args: Array[String]): Unit = {
//隐式函数将Person隐式转换为PersonWorker类
implicitdefpersonWorker(person: Person) = new PersonWorker(person)
//Person类的对象并不存在work方法,此时便会发生隐式转换,将Person类转换成PersonWorker
val persoon = new Person("小明").work
}
输出结果:
I am 小明,I am programmer.
3.2 隐式转换不会发生
在什么时候不会发生隐式转换呢,主要有一下几种情况。
(1) 编译器可以在没有隐式转换时编译通过,则不进行隐式转换。
//下面几条语句,不需要自己定义隐式转换编译就可以通过
//因此它不会发生前面定义的隐式转换
(2) 如果转换存在二义性,不会发生隐式转换。
编译提示隐式转换存在二义性(ambiguous),程序是编译不通过的。
(3) 隐式转换不会嵌套进行,嵌套时编译会出错。
object ImplicitParameterDemo {
class PersonInfoFormat(varstartSymbol: String, varendSymbol: String) {}
class Person(varname: String, varage: Int) {
//利用柯里化函数的定义方式,将函数的参数利用implicit关键字标识的话,在使用的时候可以不给出implicit对应的参数
def formatPerson()(implicitformat: PersonInfoFormat) = {
format.startSymbol+"Name:"+this.name+",age:"+this.age+format.endSymbol
}
}
def main(args: Array[String]): Unit = {
//程序中定义的变量PersonInfoFormat被称隐式值
implicit val personFormat = new PersonInfoFormat("[", "]")
val person: Person = new Person("小明", 22);
val personInfo = person.formatPerson()
println(personInfo)
}
}
输出结果:
[Name:小明,age:22]
隐式类与旧的隐式转换的语法(implicitdef)是有细微的不同的,隐式类的运作方式是:隐式类的主构造函数只能有一个参数(有两个以上并不会报错,但是这个隐式类永远不会被编译器作为隐式类在隐式转化中使用),且这个参数的类型就是将要被转换的目标类型。从语义上这很自然:这个隐式转换类将包裹目标类型,隐式类的所有方法都会自动“附加”到目标类型上。