作者:摇摆少年梦

配套视频地址:http://www.xuetuwuyou.com/course/12

本节主要内容

  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,从而得到的结果是6
implicit val x:Int=3
//不能定义两个隐式值
//implicit val y:Int=4
println(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").read2
println(f)

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

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 ClassD object 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语言能力,请大胆使用

加入公众微信号,能够了解很多其它最新Spark、Scala相关技术资讯

Scala入门到精通——第十九节 隐式转换与隐式參数(二)的更多相关文章

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

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

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

    作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...

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

    本节主要内容 泛型(Generic Type)简单介绍 注解(Annotation)简单介绍 注解经常使用场景 1. 泛型(Generic Type)简单介绍 泛型用于指定方法或类能够接受随意类型參数 ...

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

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

  5. Simulink仿真入门到精通(十九) 总结回顾&自我练习

    从2019年12月27到2020年2月12日,学习了Simulink仿真及代码生成技术入门到精通,历时17天. 学习的比较粗糙,有一些地方还没理解透彻,全书梳理总结: Simulink的基础模块已基本 ...

  6. Scala入门到精通

    原文出自于: http://my.csdn.net/lovehuangjiaju 感谢! 也感谢,http://m.blog.csdn.net/article/details?id=52233484 ...

  7. 第三百八十九节,Django+Xadmin打造上线标准的在线教育平台—列表筛选结合分页

    第三百八十九节,Django+Xadmin打造上线标准的在线教育平台—列表筛选结合分页 根据用户的筛选条件来结合分页 实现原理就是,当用户点击一个筛选条件时,通过get请求方式传参将筛选的id或者值, ...

  8. 第三百七十九节,Django+Xadmin打造上线标准的在线教育平台—xadmin的安装

    第三百七十九节,Django+Xadmin打造上线标准的在线教育平台—xadmin的安装 xadmin介绍 xadmin是基于Django的admin开发的更完善的后台管理系统,页面基于Bootstr ...

  9. 第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能

    第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能 Django实现搜索功能 1.在Django配置搜索结果页的路由映 ...

随机推荐

  1. 查看activity task相关信息

    可以使用命令 adb shell dumpsys activity 查看的结果如下 ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents ...

  2. amaze ui响应式辅助

    amaze ui响应式辅助 响应式辅助 就是不同的显示屏幕,或者手机的横竖屏,你可以控制栏目的显影,还是挺有帮助的 视口大小 .am-[show|hide]-[sm|md|lg][-up|-down| ...

  3. 73.node.js开发错误——TypeError: Cannot set property 'XXX' of undefined

    转自:https://blog.csdn.net/fd214333890/article/details/53467429

  4. three.js 运行3D模型

    HTML  <!DOCTYPE html> <html style="height: 100%;"> <head> <title>m ...

  5. 网页中插入javascript的几种方法

    网页中插入javascript的方法常见的有两种: 一.直接使用html标记 JavaScript 可以出现在 html的任意地方.使用标记<script>…</script> ...

  6. Looksery Cup 2015

    A题水 C题 博弈论,如果不是CF有WA具体哪个点错了和数据的话,AC要难许多. 如果D的操作数大于奇数个数直接Win 偶数个数大于等于n – k 时,S直接Win 偶数个数小于n – k时,若D操作 ...

  7. 认识Linux瘦客户机

           (本文完整版见http://os.51cto.com/art/201001/181448.htm)        随着Linux的发展,以及网络计算技术的发展和逐步深入的云计算,基于Li ...

  8. 博弈论 SG函数(模板) HDU 1848 Fibonacci again and again

    Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  9. 关于css的入门知识

    css:叠层样式表,给html添加样式的 接下来说一说,在网页中如何嵌套style样式 1.行间样式:把style(*权重1000)作为属性卸载标签里 eg:<p style="col ...

  10. 一起talk C栗子吧(第三十四回:C语言实例--巧用溢出计算最值)

    各位看官们.大家好,上一回中咱们说的是巧用移位的样例,这一回咱们说的样例是:巧用溢出计算最值. 闲话休提,言归正转.让我们一起talk C栗子吧! 大家都知道,程序中的变量都有一个取值范围,这个范围也 ...