作者:摇摆少年梦

配套视频地址: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. Volitale

    例1 volatile提醒编译器它后面所定义的变量随时都有可能改变.因此编译后的程序每次须要存储或读取这个变量的时候,都会直接从变量地址中读取数据. 假设没有volatile关键字.则编译器可能优化读 ...

  2. linux c statfs系统调用

    statfs 系统调用原型: int statfs(const char *path, struct statfs *buf); 參数说明: path : 位于须要查询信息的文件系统的路径名(不是设备 ...

  3. shape-自绘制简单图形

    shape 可以绘制简单的图形,颜色等.它主要就是应用于selector 的一些状态. 本文内容参考自http://www.cnblogs.com/cyanfei/archive/2012/07/27 ...

  4. The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.

    https://stackoverflow.com/questions/30045871/sorting-the-view-based-on-frequency-in-sql-server Just ...

  5. 6.Maven之(六)setting.xml配置文件详解

    转自:https://blog.csdn.net/u012152619/article/details/51485152

  6. git 版本管理工具说明

    $ git init                 (初始化本地仓库,会生成.git 文件夹  .git 文件夹里存储了所有的版本信息.标记等内容) $ git add .              ...

  7. c# Dictionary

    Dictionary<string,string>是一个泛型  有集合的功能,也可以看成一个数组:结构是这样的Dictionary<[key],[value]> 存入的对象是需 ...

  8. ps---报告当前系统的进程状态

    ps aux最初用到Unix Style中,而ps -ef被用在System V Style中,两者输出略有不同.现在的大部分Linux系统都是可以同时使用这两种方式的. linux上进程有5种状态: ...

  9. logname---显示用户名称

    logname命令用来显示用户名称.

  10. Python线程池任务

    #!/usr/bin/env python # -*- coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor #线程池, ...