一.本章要点

  • 隐式转换用于类型之间的转换  
  • 必须引入隐式转换,并确保它们可以以单个标识符的形式出现在当前作用域
  • 隐式参数列表会要求指定类型的对象。它们可以从当前作用域中以单个标识符定义的隐式对象的获取,或者从目标类型的伴生对象获取;
  • 如果隐式参数是一个单参数的函数,那么它同时也会被作为隐式转换使用
  • 类型参数的上下文界定要求存在一个指定类型的隐式对象
  • 如果有可能定位到一个隐式对象,这一点可以作为证据证明某个类型转换是合法的

二.隐式转换

  隐式转换函数指以implicit关键字声明的带有单个参数的函数。函数将被自动应用,将值从一种类型转换为另一种类型。例:

//将整数转换为分数
implicit def int2Fraction(n:Int)=Fraction(n,1)
//将自动调用int2Fraction(3),隐式转换为Fraction对象(转换函数名称可以随便,但是建议source2Target)
val result=3*Fraction(4,5)

三.利用隐式转换丰富现有类库的功能

  在Scala中,可以定义一个经过丰富的类型,提供自己想要的功能。例:

class RichFile(val from:File){
def read=Source.fromFile(from.getPath).mkString
}
//将原来的类型转换为新的类型,就可以在File对象上调用read方法了
implicit def file2RichFile(from:File)=new RichFile(from)

四.引入隐式转换

  Scala会考虑引入如下隐式函数:

    1.位于源或目标类型的伴生对象中的隐式函数;

    2.位于当前作用域可以以单个标识符指代的隐式函数

  如以上定义的int2Fraction函数,可以八它放在Fraction的伴生对象中,或者放到FractionConversions对象中(使用时需要引用它下面的方法才行,否则只能呢个以FractionConversions.int2Fraction调用如import com.horstmann.impatient.FractionConversions._而不是import com.horstman.impatient.FractionConversions)

  小技巧:在REPL中,输入:implicits查看所有除Predef引入的隐式成员,或者implicits -v查看全部  

五.隐式转换规则

  隐式转换在以下三种情况会被考虑:

      • 当表达式的类型与预期的类型不同时(如sqrt(Fraction(1,4))调用fraction2Double,因为sqrt预期是一个Double);
      • 当对象访问一个不存在的成员时(new File("README").read//将调用file2RichFile,因为File没有read方法);
      • 当对象调用某个方法,而该方法的参数声明与传入参数不匹配时:3×Fraction(4,5)//将调用int2Fraction,因为Int的*方法不接受Fraction作为参数

  不会尝试使用隐式转换:

      • 如果代码能够在不使用隐式转换的前提下通过编译,则不会使用隐式转换。例:如果a*b能够编译,那么编译器就不会尝试a*convert(b)或convert(a)*b;
      • 编译器不会尝试同时执行多个转换,比如convert1(convert2(a))*b;
      • 存在二义性的转换是个错误。如:如果convert1(a)*b和convert2(a)*b都是合法的,编译器将报错

    

Function(3,4)*5
//有如下两个表达式
Fraction(3,4)*intFraction(5)
fraction2Double(Fraction(3,4))*5
//都是合法的,这里不存在二义性,第一个转换胜出,不需要改变被应用*方法的那个对象

  小技巧:使用scala -Xprint:typer xxx.scala编译可以看到加入隐式转换的源码

六.隐式参数

  函数或方法可以带有一个标记为implicit的参数列表。这种情况下,编译器将会查找缺省值,提供给该函数或方法。例:

case class Delimiters(left:String,right:String)
def quote(what:String)(implicit delims:Delimiters)=delims.left+what+delims.right
//用一个显示的Delimiters对象来调用quote方法,如
quote("xxx")(Delimiters("xx","xx"))
//这是有两个参数列表,这个函数是”柯里化的“,可以略去隐式参数列表
quote("xxx")
/*
注:在上种情况,编译器会查找一个类型为Delimiters的隐式值(必须是一个被申明为implicit的值),会在如下两个地方查找:
1.在当前作用域所有可以单个标识符指代的满足类型要求的val和def;
2.在所有求类型相关联的类型的伴生对象。相关联的类型包括所要求类型本身,以及它的类型参数(如果是一个参数化的类型)
*/

七.利用隐式参数进行隐式转换

  隐式的函数参数也可以被用做隐式转换。例:

//错误,不知道a和b属于一个带有<操作符的类型
def smaller[T]a(a:T,b:T)=if(a<b) a else b //使用implicit如下,Ordered[T]特质有一个接受T作为参数的<操作符(十分常见,Predef对象对大量已知类型都定义了T=>Ordered[T],因此能调用smaller(1,2),smaller("Hello","HI"))
def smaller[T](a:T,b:T)(impicit order:T=>Ordered[T])=if (order(a)<b) a else b

八.上下文界定

  类型参数可以有一个形式为T:M的上下文界定,其中M是另一个泛型类型。要求作用域中存在一个类型为M[T]的隐式值。例:class Pair[T:Ordering]

  要求存在一个类型为Ordering[T]的隐式值。该隐式值可以被用在该类的方法当中,例:

class Pair[T:Ordering](val first:T,val secend:T){
def samller(implicit ord:Ordering[T])={
if (ord.compare((first,secend)<0) first else secend
}
}

  。。。

九.类型证明

  要使用类似T=:=U...这些类型参数,需要提供一个隐式参数,例:

def firstLast[A,C](it:C)(implicit ev:C<:<Iterable[A])=(it.head,it.last)

  。。。。。。

十.@implicitNotFound注解

  @implicitNotFound注解告诉编译器在不能构造出带有该注解的类型的参数时给出错误提示,例:

  

十一.CanBuildForm解读

  map是一个Iterable[A,Repr]的方法,例:

  CanBuildForm[From,E,To]特质将提供类型证明,可以创建一个类型为To的集合,握有类型为E的值,并且和类型From兼容。还带有一个apply方法,产出类型为Builder[E,To]的对象,Builder类型带有一个+=方法用来将元素添加到一个内部的缓冲,还有一个result方法用来求产出所要求的集合。。。  

十二.练习

Scala学习二十一——隐式转换和隐式参数的更多相关文章

  1. Scala学习之路 (八)Scala的隐式转换和隐式参数

    一.概念 Scala 2.10引入了一种叫做隐式类的新特性.隐式类指的是用implicit关键字修饰的类.在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换. 隐式转换和隐式参数是Scal ...

  2. Spark基础-scala学习(八、隐式转换与隐式参数)

    大纲 隐式转换 使用隐式转换加强现有类型 导入隐式转换函数 隐式转换的发生时机 隐式参数 隐式转换 要实现隐式转换,只要程序可见的范围内定义隐式转换函数即可.Scala会自动使用隐式转换函数.隐式转换 ...

  3. Scala入门到精通——第十九节 隐式转换与隐式參数(二)

    作者:摇摆少年梦 配套视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 隐式參数中的隐式转换 函数中隐式參数使用概要 隐式转换问题梳理 1. 隐式參数中的 ...

  4. 大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值

    第八章 面向对象编程-高级8.1 静态属性和静态方法8.1.1 静态属性-提出问题8.1.2 基本介绍8.1.3 伴生对象的快速入门8.1.4 伴生对象的小结8.1.5 最佳实践-使用伴生对象解决小孩 ...

  5. Scala隐式转换和隐式参数

    隐式转换 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象或者是给一个类增加方法.通过这些功能, ...

  6. 12、scala隐式转换与隐式参数

    一.隐式转换 1.介绍 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象. 通过这些功能,可以实 ...

  7. Scala 中的隐式转换和隐式参数

    隐式定义是指编译器为了修正类型错误而允许插入到程序中的定义. 举例: 正常情况下"120"/12显然会报错,因为 String 类并没有实现 / 这个方法,我们无法去决定 Stri ...

  8. Scala基础:闭包、柯里化、隐式转换和隐式参数

    闭包,和js中的闭包一样,返回值依赖于声明在函数外部的一个或多个变量,那么这个函数就是闭包函数. val i: Int = 20 //函数func的方法体中使用了在func外部定义的变量 那func就 ...

  9. 02.Scala高级特性:第6节 高阶函数;第7节 隐式转换和隐式参数

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

随机推荐

  1. fiddler 基本知识(一)

    工作原理: fiddler,原理是在本机开启了一个http代理服务器,默认监听127.0.0.1:8888. 打开fiddler之后,会帮我们设置ie代理,虽然只设置了ie,但整个计算机都通过整个代理 ...

  2. Java同步数据结构之Map概述及ConcurrentSkipListMap原理

    引言 前面介绍了CopyOnWriteArraySet,本来接着是打算介绍ConcurrentSkipListSet,无耐ConcurrentSkipListSet的内部实现其实是依赖一个Concur ...

  3. java+大文件分段上传

    一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...

  4. PhpStorm设置项目编码

    因为工作中论坛项目用的是GBK编码.数据库也是GBK编码.模板也是GBK,所以为了以后修改程序不出现乱码问题,所以需要把我的PhpStorm中该项目也设置为GBK编码(默认是UTF8编码). 设置路径 ...

  5. leetcode mysql

    给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值.交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然).要求只使用一个更新(Update)语句,并且没有 ...

  6. Had I not seen the Sun(如果我不曾见过太阳)

    Had I not seen the Sun by Emily Dickinson Had I not seen the Sun I could have borne the shade But Li ...

  7. 【首发】uExitCode解释

    uExitCode 进程退出码,一般设置为0,不是的话也没有错误. 它的主要作用是,通知调用这个程序的其他程序退出的原因. 以前在dos下可能用的较多,现在windows下用的很少,而且windows ...

  8. 模板引擎doT.js用法详解

    作为一名前端攻城师,经常会遇到从后台ajax拉取数据再显示在页面的情境,一开始我们都是从后台拉取再用字符串拼接的方式去更达到数据显示在页面! <!-- 显示区域 --> <div i ...

  9. springBoot--组合注解RestController,GetMapping,PostMapping

    一.RestController @RestController 是@Controller和@ResponseBody的缩写 二.@getMapping和PostMapping @GetMapping ...

  10. 第24课.经典问题解析(1.析构函数的顺序;2.const修饰对象;3.成员函数,成员变量是否属于具体对象)

    1.当程序中存在多个对象的时候,如何确定这些对象的析构顺序? 单个对象 单个对象创建时构造函数的调用顺序 a.调用父类的构造函数 b.调用成员变量的构造函数(调用顺序与声明顺序相同) c.调用类自身的 ...