Scala入门到精通——第十九节 隐式转换与隐式参数(二)
本节主要内容
- 隐式参数中的隐式转换
- 函数中隐式参数使用概要
- 隐式转换问题梳理
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入门到精通——第十九节 隐式转换与隐式参数(二)相关推荐
- Scala入门到精通——第二十九节 Scala数据库编程
本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...
- Scala入门到精通——第十四节 Case Class与模式匹配(一)
本节主要内容 模式匹配入门 Case Class简介 Case Class进阶 1. 模式匹配入门 在Java语言中存在switch语句,例如: //下面的代码演示了java中switch语句的使用 ...
- Scala入门到精通——第二十六节 Scala并发编程基础
本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 1. Scala并发编程简介 2003 年,Herb Sutte ...
- Scala入门到精通——第二十四节 高级类型 (三)
本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...
- Scala入门到精通——第二十五节 提取器(Extractor)
本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...
- Scala入门到精通——第十六节 泛型与注解
本节主要内容 泛型(Generic Type)简介 注解(Annotation)简介 注解常用场景 1. 泛型(Generic Type)简介 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用 ...
- Scala入门到精通——第十五节 Case Class与模式匹配(二)
本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{def main(args: Arra ...
- Scala入门到精通——第十八节 隐式转换与隐式参数(一)
本节主要内容 隐式转换简介 隐式转换函数 隐式转换规则 隐式参数 1. 隐式转换简介 在Scala语言当中,隐式转换是一项强大的程序语言功能,它不仅能够简化程序设计,也能够使程序具有很强的灵活性.要想 ...
- Scala入门到精通——第二十节 类型参数(二)
本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...
最新文章
- 院士:科研工作者也得养家,非升即走压力下,不得不做短平快的研究
- 基于TableStore的数据采集分析系统介绍
- 什么是Python的var_dump()的Python等价物? [重复]
- mysql 环形复制_mysql复制(Replication)
- Stumpwm的编译安装
- Java问题排查工具箱
- apt-get could not get lock /var/lib/dpkg/lock报错
- 树莓派运行python import os未找到命令_通过pip指令在树莓派上基于Python3安装OpenCV...
- php like %%,thinkphp实现like模糊查询实例
- [转]如何使用BackTrack破解WIFI无线网络的WEP密钥
- IDEA14创建Maven管理的Java Web项目
- 【CF1325E】 Ehab's REAL Number Theory Problem(思维+最小环bfs)
- 卡尔曼滤波和互补滤波的区别
- Java实现POS打印机无驱打印(转)
- 清华大学朱小燕教授做客雷锋网沙龙,分享 NLP 和人工智能的那些事儿| AAAI 2017...
- 高数_第6章无穷级数__幂级数_收敛点收敛域收敛半径
- 微信+html5+播放音频+自动播放,html5音频实现微信语音播放效果
- CSS揭破实用窍门总结
- Android实战——简单网络视频播放器
- linux文件系统与模型【笔记】 surper block/inode/dentry/file
热门文章
- 【最详细】数据结构(C语言版 第2版)第二章课后习题答案 严蔚敏 等 编著
- 算法竞赛入门经典(第二版) | 例题5-1 大理石在哪 (普适查找)(UVa10474,Where is the Marble?)
- linux vi模式替换,linux基础命令之:vi模式下查找和替换
- php实现二叉搜索树,二叉搜索树有几种实现方式
- MySQL——高阶语句(中)
- java 向已存在的excel中追加数据 .
- python 循环语句结果存储_Python条件语句和循环语句
- oracle sql 分区查询语句_oracle11g 表分区后的查询语句如何知道是否进行了全表扫描...
- python自带gui_Python GUI开发工具中五种类型的相关介绍
- 以array开头的php函数,PHP 常用数组函数详解