scala隐式转换1
2017-08-17 00:00
197 查看
摘要: 一部分内容验证过,并针对自己的疑问作了点解释
摘要:
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。
使用方式:
1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicit
Scala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功
隐式解析机制
即编译器是如何查找到缺失信息的,解析具有以下两种规则:
1.首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象)
2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
(1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索
(2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的
伴生对象和String的伴生对象
(3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索
(4) 如果T是个类型注入S#T,那么S和T都会被搜索
隐式参数与隐式值:
例1:声明person方法。其参数为name,类型String
直接调用person方法
报错!编译器说无法为参数name找到一个隐式值
定义一个隐式值后再调用person方法
因为将p变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺少参数。
但是如果此时你又在REPL中定义一个隐式变量,再次调用方法时就会报错
匹配失败,所以隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配
隐式视图
隐式转换为目标类型:把一种类型自动转换到另一种类型
例2:将整数转换成字符串类型:
显然不能转换成功,解决办法就是定义一个转换函数给编译器将int自动转换成String
注意:不能存在两个转换的隐式函数,如还定义了一个函数:
//toString加不加”()“都是可以的
implicit def intToString2(x: Int) = x.toString() + "second function"
这样在IDE中就会报错无法解析。
隐式转换调用类中本不存在的方法
例3:通过隐式转换,使对象能调用类中本不存在的方法
编译器在rabbit对象调用时发现对象上并没有wantLearning方法,此时编译器就会在作用域范围内查找能使其编译通过的隐式视图,找到learningType方法后,编译器通过隐式转换将对象转换成具有这个方法的对象,之后调用wantLearning方法
可以将隐式转换函数定义在伴生对象中,在使用时导入隐式视图到作用域中即可(如例3的learningType函数)
还可以将隐式转换函数定义在兄对象中,同样在使用时导入作用域即可,如例4
例4:
像intToString,learningType这类的方法就是隐式视图,通常为Int => String的视图,定义的格式如下:
implicit def originalToTarget ( : OriginalType) : TargetType
其通常用在于以两种场合中:
1.如果表达式不符合编译器要求的类型,编译器就会在作用域范围内查找能够使之符合要求的隐式视图。如例2,当要传一个整数类型给要求是字符串类型参数的方法时,在作用域里就必须存在Int => String的隐式视图
2.给定一个选择e.t,如果e的类型里并没有成员t,则编译器会查找能应用到e类型并且返回类型包含成员t的隐式视图。如例3
隐式类:
在scala2.10后提供了隐式类,可以使用implicit声明类,但是需要注意以下几点:
1.其所带的构造参数有且只能有一个
2.隐式类必须被定义在类,伴生对象和包对象里
3.隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾)
4.作用域内不能有与之相同名称的标示符
例5:
编译器在mobin对象调用increment时发现对象上并没有increment方法,此时编译器就会在作用域范围内搜索隐式实体,发现有符合的隐式类可以用来转换成带有increment方法的StringImprovement类,最终调用increment方法。
隐式转换的时机:
1.当方法中的参数的类型与目标类型不一致时
2.当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
隐式转换的前提:
1.不存在二义性(如例1)
2.隐式操作不能嵌套使用(如 convert1(covert2(x)))+y
3.代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式黑铁
摘要:
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。
使用方式:
1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicit
Scala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功
隐式解析机制
即编译器是如何查找到缺失信息的,解析具有以下两种规则:
1.首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象)
2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
(1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索
(2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的
伴生对象和String的伴生对象
(3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索
(4) 如果T是个类型注入S#T,那么S和T都会被搜索
隐式参数与隐式值:
例1:声明person方法。其参数为name,类型String
scala> def person(implicit name : String) = name //name为隐式参数 person: (implicit name: String)String
直接调用person方法
scala> person :9: error: could not find implicit value for parameter name: String person ^
报错!编译器说无法为参数name找到一个隐式值
定义一个隐式值后再调用person方法
scala> implicit val p = "mobin" //p被称为隐式值 p: String = mobin scala> person res1: String = mobin
因为将p变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺少参数。
但是如果此时你又在REPL中定义一个隐式变量,再次调用方法时就会报错
scala> implicit val p1 = "mobin1" p1: String = mobin1 scala> person :11: error: ambiguous implicit values: both value p of type => String and value p1 of type => String match expected type String person ^
匹配失败,所以隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配
隐式视图
隐式转换为目标类型:把一种类型自动转换到另一种类型
例2:将整数转换成字符串类型:
scala> def foo(msg : String) = println(msg) foo: (msg: String)Unit scala> foo(10) :11: error: type mismatch; found : Int(10) required: String foo(10) ^
显然不能转换成功,解决办法就是定义一个转换函数给编译器将int自动转换成String
scala> implicit def intToString(x : Int) = x.toString intToString: (x: Int)String scala> foo(10) 10
注意:不能存在两个转换的隐式函数,如还定义了一个函数:
//toString加不加”()“都是可以的
implicit def intToString2(x: Int) = x.toString() + "second function"
这样在IDE中就会报错无法解析。
隐式转换调用类中本不存在的方法
例3:通过隐式转换,使对象能调用类中本不存在的方法
class SwingType{ def wantLearned(sw : String) = println("兔子已经学会了"+sw) } object swimming{ implicit def learningType(s : AminalType) = new SwingType } class AminalType object AminalType extends App{ import com.mobin.scala.Scalaimplicit.swimming._ val rabbit = new AminalType rabbit.wantLearned("breaststroke") //蛙泳 }
编译器在rabbit对象调用时发现对象上并没有wantLearning方法,此时编译器就会在作用域范围内查找能使其编译通过的隐式视图,找到learningType方法后,编译器通过隐式转换将对象转换成具有这个方法的对象,之后调用wantLearning方法
可以将隐式转换函数定义在伴生对象中,在使用时导入隐式视图到作用域中即可(如例3的learningType函数)
还可以将隐式转换函数定义在兄对象中,同样在使用时导入作用域即可,如例4
例4:
class SwingType{ def wantLearned(sw : String) = println("兔子已经学会了"+sw) } package swimmingPage{ object swimming{ implicit def learningType(s : AminalType) = new SwingType //将转换函数定义在包中 } } class AminalType object AminalType extends App{ import com.mobin.scala.Scalaimplicit.swimmingPage.swimming._ //使用时显示的导入 val rabbit = new AminalType rabbit.wantLearned("breaststroke") //蛙泳 }
像intToString,learningType这类的方法就是隐式视图,通常为Int => String的视图,定义的格式如下:
implicit def originalToTarget ( : OriginalType) : TargetType
其通常用在于以两种场合中:
1.如果表达式不符合编译器要求的类型,编译器就会在作用域范围内查找能够使之符合要求的隐式视图。如例2,当要传一个整数类型给要求是字符串类型参数的方法时,在作用域里就必须存在Int => String的隐式视图
2.给定一个选择e.t,如果e的类型里并没有成员t,则编译器会查找能应用到e类型并且返回类型包含成员t的隐式视图。如例3
隐式类:
在scala2.10后提供了隐式类,可以使用implicit声明类,但是需要注意以下几点:
1.其所带的构造参数有且只能有一个
2.隐式类必须被定义在类,伴生对象和包对象里
3.隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾)
4.作用域内不能有与之相同名称的标示符
例5:
object Stringutils { implicit class StringImprovement(val s : String){ //隐式类 def increment = s.map(x => (x +1).toChar) } } object Main extends App{ import com.mobin.scala.implicitPackage.Stringutils._ println("mobin".increment) }
编译器在mobin对象调用increment时发现对象上并没有increment方法,此时编译器就会在作用域范围内搜索隐式实体,发现有符合的隐式类可以用来转换成带有increment方法的StringImprovement类,最终调用increment方法。
隐式转换的时机:
1.当方法中的参数的类型与目标类型不一致时
2.当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
隐式转换的前提:
1.不存在二义性(如例1)
2.隐式操作不能嵌套使用(如 convert1(covert2(x)))+y
3.代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式黑铁
相关文章推荐
- Step into Scala - 26 - 隐式参数,隐式转换与 DSL
- scala隐式转换
- scala implicit 隐式转换
- 深入理解Scala的隐式转换系统
- 学习Scala:Map初始化过程详解及隐式类型转换
- 【scala 笔记(9)】 隐式转换 和 隐式参数-- implicit
- Scala隐式转换几种使用场景
- Scala中的Implicit(隐式转换,隐式参数,隐式类)
- scala 隐式转换
- Scala学习笔记--隐式类型和隐式转换
- 关于 Scala 隐式转换必读的一篇官方圣典
- scala基础之隐式转换
- Scala学习—隐式转换与隐式参数
- 第61讲 scala 中隐式转换执行过程分析
- 第66讲scala 中伴生对象的隐式转换
- Scala隐式转换实战
- Scala学习整理[第二十-二十一章 抽象成员和隐式转换]<Programming In Scala>
- 转载:深入理解Scala的隐式转换系统
- 3000门徒内部训练绝密视频(泄密版)第5课:彻底精通Scala隐式转换和并发编程及Spark源码阅读
- 扒一扒scala隐式转换