本节主要内容

  1. 隐式参数中的隐式转换
  2. 函数中隐式参数使用概要
  3. 隐式转换问题梳理

1. 隐式参数中的隐式转换

前一讲中,我们提到函数中如果存在隐式参数,在使用该函数的时候如果不给定对应的参数,则编译器会自动帮我们搜索相应的隐式值,并将该隐式值作为函数的参数,这里面其实没有涉及到隐式转换,本节将演示如何利用隐式参数进行隐式转换,下面的代码给定的是一个普通的比较函数:

object ImplicitParameter extends App {//下面的代码不能编译通过
//这里面泛型T没有具体指定,它不能直接使用
//<符号进行比较def compare[T](first:T,second:T)={if (first < second) first else second}
}

上面的代码要想使其编译通过,可以前类型变量界定和视图界定指定其上界为Ordered[T],例如:

object ImplicitParameter extends App {//指定T的上界为Ordered[T],所有混入了特质Ordered//的类都可以直接的使用<比较符号进行比较def compare[T<:Ordered[T]](first:T,second:T)={if (first < second) first else second}
}

这是一种解决方案,我们还有一种解决方案就是通过隐式参数的隐式转换来实现,代码如下:

object ImplicitParameter extends App {//下面代码中的(implicit order:T=>Ordered[T])
//给函数compare指定了一个隐式参数
//该隐式参数是一个隐式转换def compare[T](first:T,second:T)(implicit order:T=>Ordered[T])={if (first > second) first else second}println(compare("A","B"))
}

2. 函数中隐式参数使用概要

要点1:在定义函数时,如果函数没有柯里化,implicit关键字会作用于所有参数,例如:

//implicit关键字在下面的函数中只能出现一次
//它作用于两个参数x,y,也即x,y都是隐式参数
def sum(implicit x: Int, y: Int) = x + y
//下面的函数不合法,函数如果没有柯里化,不能期望
//implicit关键字会作用于其中一个参数
//def sum(x: Int, implicit y: Int) = x + y
//def sum(implicit x: Int, implicit y: Int) = x + y

另外,值得注意的是,def maxFunc(implicit x: Int, y: Int) = x + y 在使用时,也只能指定一个隐式值,即指定的隐式值分别会对应函数中的参数(这里是x,y),代码如下:

def sum(implicit x: Int, y: Int) = x + y
//只能指定一个隐式值
//例如下面下定义的x会自动对应maxFunc中的
//参数x,y即x=3,y=3,从而得到的结果是6implicit val x:Int=3
//不能定义两个隐式值
//implicit val y:Int=4println(sum)

要点2:要想使用implicit只作用于某个函数参数,则需要将函数进行柯里化,如:

def sum(x: Int)(implicit y:Int)=x+y

值得注意的是,下面这种两种带隐式参数的函数也是不合法的

def sum(x: Int)(implicit y:Int)(d:Int)=x+y+d
def sum(x: Int)(implicit y:Int)(implicit d:Int)=x+y+d

要点3: 匿名函数不能使用隐式参数,例如:

 val sum2=(implicit x:Int)=>x+1

要点4: 如何函数带有隐式参数,则不能使用其偏函数,例如:

def sum(x: Int)(implicit y:Int)=x+y
 //不能定义sum的偏函数,因为它带有隐式参数
 //could not find implicit value for
//parameter y: Int
//not enough arguments for method sum:
// (implicit y: Int)Int. Unspecified value parameter y.def sum2=sum _

3. 隐式转换问题梳理

1 多次隐式转换问题
在上一讲中我们提到,隐式转换从源类型到目标类型不会多次进行,也即源类型到目标类型的转换只会进行一次

class RichFile(val file:File){def read=Source.fromFile(file).getLines().mkString
}//RichFileAnother类,里面定义了read2方法
class RichFileAnother(val file:RichFile){def read2=file.read
}//隐式转换不会多次进行,下面的语句会报错//不能期望会发生File到RichFile,然后RifchFile到//RichFileAnthoer的转换val f=new File("file.log").read2println(f)
  • 1

注意这里指的是源类型到目标类型的转换只会进行一次,并不是说不存在多次隐式转换,在一般的方法调用过程中可能会出现多次隐式转换,例如:

class ClassA {override def toString() = "This is Class A"
}
class ClassB {override def toString() = "This is Class B"
}
class ClassC {override def toString() = "This is  ClassC"def printC(c: ClassC) = println(c)
}
class ClassDobject ImplicitWhole extends App {implicit def B2C(b: ClassB) = {println("B2C")new ClassC}implicit def D2C(d: ClassD) = {println("D2C")new ClassC}//下面的代码会进行两次隐式转换//因为ClassD中并没有printC方法//因为它会隐式转换为ClassC(这是第一次,D2C)//然后调用printC方法//但是printC方法只接受ClassC类型的参数//然而传入的参数类型是ClassB//类型不匹配,从而又发生了一次隐式转地换(这是第二次,B2C)//从而最终实现了方法的调用new ClassD().printC(new ClassB)
}

还有一种情况也会发生多次隐式转换,如果给函数定义了隐式参数,在实际执行过程中可能会发生多次隐式转换,代码如下:

object Main extends App {class PrintOps() {def print(implicit i: Int) = println(i);}implicit def str2PrintOps(s: String) = {println("str2PrintOps")new PrintOps}implicit def str2int(implicit s: String): Int = {println("str2int")Integer.parseInt(s)}implicit def getString = {println("getString")"123"}//下面的代码会发生三次隐式转换//首先编译器发现String类型是没有print方法的//尝试隐式转换,利用str2PrintOps方法将String//转换成PrintOps(第一次)//然后调用print方法,但print方法接受整型的隐式参数//此时编译器会搜索隐式值,但程序里面没有给定,此时//编译器会尝试调用 str2int方法进行隐式转换,但该方法//又接受一个implicit String类型参数,编译器又会尝试//查找一个对应的隐式值,此时又没有,因此编译器会尝试调用//getString方法对应的字符串(这是第二次隐式转换,//获取一个字符串,从无到有的过程)//得到该字符串后,再调用str2int方法将String类型字符串//转换成Int类型(这是第三次隐式转换)"a".print
}

2 要不要用隐式转换的问题

从上述代码中可以看到,隐式转换功能很强大,但同时也带来了程序复杂性性问题,在一个程序中如果大量运用隐式转换,特别是涉及到多次隐式转换时,会使代码理解起来变得比较困难,那到底要不要用隐式转换呢?下面给出我自己开发实践中的部分总结,供大家参考:
1 即使你能轻松驾驭Scala语言中的隐式转换,能不用隐式转换就尽量不用
2 如果一定要用,在涉及多次隐式转换时,必须要说服自己这样做的合理性
3 如果只是炫耀自己的scala语言能力,请大胆使用

Scala入门到精通——第十九节 隐式转换与隐式参数(二)相关推荐

  1. Scala入门到精通——第二十九节 Scala数据库编程

    本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...

  2. Scala入门到精通——第十四节 Case Class与模式匹配(一)

    本节主要内容 模式匹配入门 Case Class简介 Case Class进阶 1. 模式匹配入门 在Java语言中存在switch语句,例如: //下面的代码演示了java中switch语句的使用 ...

  3. Scala入门到精通——第二十六节 Scala并发编程基础

    本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 1. Scala并发编程简介 2003 年,Herb Sutte ...

  4. Scala入门到精通——第二十四节 高级类型 (三)

    本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...

  5. Scala入门到精通——第二十五节 提取器(Extractor)

    本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...

  6. Scala入门到精通——第十六节 泛型与注解

    本节主要内容 泛型(Generic Type)简介 注解(Annotation)简介 注解常用场景 1. 泛型(Generic Type)简介 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用 ...

  7. Scala入门到精通——第十五节 Case Class与模式匹配(二)

    本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{def main(args: Arra ...

  8. Scala入门到精通——第十八节 隐式转换与隐式参数(一)

    本节主要内容 隐式转换简介 隐式转换函数 隐式转换规则 隐式参数 1. 隐式转换简介 在Scala语言当中,隐式转换是一项强大的程序语言功能,它不仅能够简化程序设计,也能够使程序具有很强的灵活性.要想 ...

  9. Scala入门到精通——第二十节 类型参数(二)

    本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...

最新文章

  1. 院士:科研工作者也得养家,非升即走压力下,不得不做短平快的研究
  2. 基于TableStore的数据采集分析系统介绍
  3. 什么是Python的var_dump()的Python等价物? [重复]
  4. mysql 环形复制_mysql复制(Replication)
  5. Stumpwm的编译安装
  6. Java问题排查工具箱
  7. apt-get could not get lock /var/lib/dpkg/lock报错
  8. 树莓派运行python import os未找到命令_通过pip指令在树莓派上基于Python3安装OpenCV...
  9. php like %%,thinkphp实现like模糊查询实例
  10. [转]如何使用BackTrack破解WIFI无线网络的WEP密钥
  11. IDEA14创建Maven管理的Java Web项目
  12. 【CF1325E】 Ehab's REAL Number Theory Problem(思维+最小环bfs)
  13. 卡尔曼滤波和互补滤波的区别
  14. Java实现POS打印机无驱打印(转)
  15. 清华大学朱小燕教授做客雷锋网沙龙,分享 NLP 和人工智能的那些事儿| AAAI 2017...
  16. 高数_第6章无穷级数__幂级数_收敛点收敛域收敛半径
  17. 微信+html5+播放音频+自动播放,html5音频实现微信语音播放效果
  18. CSS揭破实用窍门总结
  19. Android实战——简单网络视频播放器
  20. linux文件系统与模型【笔记】 surper block/inode/dentry/file

热门文章

  1. 【最详细】数据结构(C语言版 第2版)第二章课后习题答案 严蔚敏 等 编著
  2. 算法竞赛入门经典(第二版) | 例题5-1 大理石在哪 (普适查找)(UVa10474,Where is the Marble?)
  3. linux vi模式替换,linux基础命令之:vi模式下查找和替换
  4. php实现二叉搜索树,二叉搜索树有几种实现方式
  5. MySQL——高阶语句(中)
  6. java 向已存在的excel中追加数据 .
  7. python 循环语句结果存储_Python条件语句和循环语句
  8. oracle sql 分区查询语句_oracle11g 表分区后的查询语句如何知道是否进行了全表扫描...
  9. python自带gui_Python GUI开发工具中五种类型的相关介绍
  10. 以array开头的php函数,PHP 常用数组函数详解