摘要:
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。
使用方式:
1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicit
Scala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功
隐式值:
例1:声明person方法。其参数为name,类型String
scala> def person(implicit name : String) = name   //name为隐式参数
person: (implicit name: String)String

直接调用person方法

scala> person
<console>:9: error: could not find implicit value for parameter name: Stringperson^

报错!编译器说无法为参数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
<console>:11: error: ambiguous implicit values:both value p of type => Stringand value p1 of type => Stringmatch expected type Stringperson^

匹配失败,所以隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配

隐式视图
隐式转换为目标类型:把一种类型自动转换到另一种类型
例2:将整数转换成字符串类型:
scala> def foo(msg : String) = println(msg)
foo: (msg: String)Unitscala> foo(10)
<console>:11: error: type mismatch;
found : Int(10)
required: String
foo(10)
^

显然不能转换成功,解决办法就是定义一个转换函数给编译器将int自动转换成String

scala> implicit def intToString(x : Int) = x.toString
intToString: (x: Int)Stringscala> foo(10)
10

隐式转换调用类中本不存在的方法
例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 AminalTyperabbit.wantLearned("breaststroke")         //蛙泳
}

编译器在rabbit对象调用时发现对象上并没有wantLearning方法,此时编译器就会在作用域范围内查找能使其编译通过的隐式视图,找到learningType方法后,编译器通过隐式转换将对象转换成具有这个方法的对象,之后调用wantLearning方法
可以将隐式转换函数定义在伴生对象中,在使用时导入隐式视图到作用域中即可(如例4的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 AminalTyperabbit.wantLearned("breaststroke")         //蛙泳
}

像intToString,learningType这类的方法就是隐式视图,通常为Int => String的视图,定义的格式如下:
     implicit def  originalToTarget (<argument> : 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.首先会在当前代码作用域下查找隐式实体(隐式方法  隐式类 隐式对象)
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.不存在二义性(如例1)
2.隐式操作不能嵌套使用(如 convert1(covert2(x)))+y
3.代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式黑铁

转载于:https://www.cnblogs.com/MOBIN/p/5351900.html

深入理解Scala的隐式转换相关推荐

  1. 深入理解Scala的隐式转换系统

    原文链接:http://www.cnblogs.com/MOBIN/p/5351900.html ---------------------------------------------- 摘要: ...

  2. scala之隐式转换

    目录 0.隐式转换定义 1.函数隐式转换 2.使用隐式转换加强现有类型 3.隐式转换函数的作用域与导入 4.隐式参数 5.隐式转换的发生时机 0.隐式转换定义 实现方式:隐式转换函数接收的参数类型定义 ...

  3. 大数据Saprk----Spark基础-scala的隐式转换

    first Codec **public class Friend {public static void main(String[] args){System.out.println("B ...

  4. Scala的隐式转换详解

    隐式转换是在Scala编译器进行类型匹配时,如果找不到合适的类型,那么隐式转换会让编译器在作用范围内自动推导出来合适的类型. 1.隐式值与隐式参数 隐式值是指在定义参数时前面加上implicit.隐式 ...

  5. Scala自动隐式转换

    底层实现:Scala编译器自动调用了transform方法将5.0转换成Int 在相同作用域内,不能含有多个相同类型的转换规则

  6. Scala 高阶函数(作为值的函数、匿名函数、闭包、柯里化)+隐式转换和隐式参数...

    Scala高级特性 1.    学习目标 1.1.   目标一:深入理解高阶函数 1.2.   目标二:深入理解隐式转换 2.    高阶函数 2.1.   概念 Scala混合了面向对象和函数式的特 ...

  7. scala学习之旅(十三):隐式转换和隐式参数

    文章地址:http://www.haha174.top/admin/article/list 1.引言 scala 提供的隐式转换和隐式参数功能,是非常有特色的功能.是java 等编程语言所没有的功能 ...

  8. 【Scala】Scala中的模式匹配、类型参数与隐式转换

    1.模式匹配 (1)概述 模式匹配是Scala中非常有特色,非常强大的一种功能.模式匹配,其实类似于Java中的swich case语法,即对一个值进行条件判断,然后针对不同的条件,进行不同的处理.但 ...

  9. scala当中的文件操作、网络请求和隐式转换

    scala当中的文件操作.网络请求和隐式转换 文件操作和网络请求 读取文件当中每一行的数据 读取词法单元和数字 读取网络资源.文件写入.控制台操作 读取网络资源 文件写入操作 控制台交互操作 scal ...

最新文章

  1. JavaScript创建对象的方法
  2. java主键后四位顺序号_JAVA中取顺序号 (转)
  3. 【laravel】docker 部署laravel 遇到的问题?
  4. 双极型adc与stm32_关于STM32 双ADC同步规则转换两路数据的问题?
  5. 类的带参方法有哪几部分构成?
  6. 使用Navicat管理MySQL用户
  7. Npm 恶意包试图窃取 Discord 敏感信息和浏览器文件
  8. linux修改主机名(不重启)
  9. Kubernetes 权限管理
  10. 在 Chrome 浏览器中安装印象笔记·剪藏插件
  11. 第 1 章 程序员考试简介
  12. Linux下常用软件大比拼
  13. Chrome谷歌浏览器安装与配置教程
  14. cas和saml_结合使用SAML安全令牌和Microsoft Web Services增强功能
  15. 如何设置苹果Mac菜单栏的时间与日期显示
  16. 题注中的图一.1变成图1.1
  17. 六级考研单词之路-十一
  18. 使用VUE做的个人简历
  19. 工业交换机的内部组成是什么?
  20. String类型转Long类型

热门文章

  1. oc - NSArray基础用法总结
  2. 去掉Win7资源管理器左侧不需要的项目
  3. Linux下 sshd服务不能启动
  4. spark基础之RDD详解
  5. ConsumerNetworkClient 分析
  6. (79)FPGA复位激励(initial)
  7. (50)FPGA面试技能提升篇(版本控制工具Clearcase、Git)
  8. 1004.串口收发数据集成bug
  9. 【STM32】各类通信接口及协议简识(IIC、SPI、RS232、RS485、CAN、USB)
  10. 数据结构之队列的特别实现