【Scala】什么是隐式转换?它又能用来干嘛?该怎么用
定义
隐式参数
隐式参数指在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的参数,即隐式值,并注入参数。
Scala会在两个范围进行查找:
1.当前作用域内可见的val或var定义的隐式变量
2.隐式参数类型的伴生对象内的隐式值
隐式转换
当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。
其中最核心的就是自己定义隐式转换方法(implicit conversion function),Scala会根据隐式转换方法的签名,在程序中使用到隐式转换方法接收的参数类型定义的对象时,会自动将其传入隐式转换方法,转换为另外一种类型的对象并返回。所有的隐式值和隐式方法都必须放到object中。
什么时候要进行隐式转换?
1.当对象调用类中不存早的方法或成员时,编译器会自动将对象进行隐式转换
2.当方法中的参数类型与目标类型不一致时
隐式转换的限制:
1.implicit关键字只能用来修饰方法、变量(参数)
2.隐式转换的方法在当前范围内才有效,如果隐式转换不在当前范围内定义(比如定义在了另一个类中或者包含在某个对象中),就必须通过import语句导入
隐式转换使用方式:
1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicit
隐式值:给方法提供参数
//先定义一个普通的方法
scala> def m1(name:String) = println(name)
m1: (name: String)Unit
//给定匹配的参数类型不会报错
scala> m1("LeiJun")
LeiJun
//如果给了不匹配的参数类型就会报错
scala> m1(2)
<console>:13: error: type mismatch;
found : Int(2)
required: String
m1(2)
^
//或者不给参数也会报错
scala> m1
<console>:13: error: missing argument list for method m1
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `m1 _` or `m1(_)` instead of `m1`.
m1
^
//现在重新定义一个方法,参数用implicit修饰
scala> def m2(implicit name:String) = println(name)
m2: (implicit name: String)Unit
//只输出m2依然会报错,不过和之前已经不一样了
//显示的是“找不到参数name: String的隐式值”
scala> m2
<console>:13: error: could not find implicit value for parameter name: String
m2
^
//那就定义隐式值
scala> implicit val a:String = "money"
a: String = money
//只输出m2发现发生了隐式转换
scala> m2
money
scala> m2("123")
123
//如果再定义一个同类型的隐式值
scala> implicit val b:String = "love"
b: String = love
//就会报错,“爱情面包不可兼得”
scala> m2
<console>:15: error: ambiguous implicit values:
both value a of type => String
and value b of type => String
match expected type String
m2
^
隐式视图
将Int和Double类型转换为String
scala> def m1(name:String) = println(name)
m1: (name: String)Unit
//定义一个将Int类型转换为String的隐式转换方法
scala> implicit def Int2String(x:Int) = x.toString
warning: there was one feature warning; re-run with -feature for details
Int2String: (x: Int)String
scala> m1(123)
123
//定义一个将Double类型转换为String的隐式转换方法
scala> implicit def Double2String(x:Double) = x.toString
warning: there was one feature warning; re-run with -feature for details
Double2String: (x: Double)String
scala> m1(3.14)
3.14
狗狗学技能(使用别的类中的方法)
狗狗学习导盲技能
class Learn {
def learnMore(skills:String) = println(skills)
}
// implicit 隐式转换
object Teaching{
//定义隐式转换的方法 让一个类可以调用另一个类
implicit def dogLearning(dog: Dog) = new Learn
}
class Dog{
}
object FinalDog{
def main(args: Array[String]): Unit = {
//创建Dog对象
val dog = new Dog
//手动导入隐式转换方法
import cn.itcast.scala.implicit_demo.Teaching.dogLearning
//Dog自己的类中并没有learnMore方法,通过隐式转换就可以直接调用Learn类中的方法
dog.learnMore("导盲")
}
}
使用规则
1. Scala一般指考虑处于作用域之内的隐式转换,不过可以通过import调用其他类中的方法,比如上面用到的import cn.itcast.scala.implicit_demo.Teaching.dogLearning。
2. 无歧义规则。隐式转换必须在不存在其他可插入转换的前提下才能插入。比如:
scala> implicit def String2Int(s:String) = s.toInt
warning: there was one feature warning; re-run with -feature for details
String2Int: (s: String)Int
scala> implicit def String2Double(s:String) = s.toDouble
<console>:18: error: type mismatch;
found : s.type (with underlying type String)
required: ?{def toDouble: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
and method String2Int of type (s: String)Int
are possible conversion functions from s.type to ?{def toDouble: ?}
implicit def String2Double(s:String) = s.toDouble
^
<console>:18: error: value toDouble is not a member of String
Note: implicit method String2Double is not applicable here because it comes after the application point and it lacks an explicit result type
implicit def String2Double(s:String) = s.toDouble
^
上面两个都想通过隐式转换同时将String类型转换为Int和Double,如果要进行转换运算时,就会产生歧义,scala会不明白到底是要将输入的String类型参数转换为Int类型还是Double类型
3. 单一调用原则。scala只会尝试一个隐式操作,不会对某个变量执行多次隐式转换。
比如说,现在想将输入的String类型参数转换为Int,然后定义了一个将String类型隐式转换为Int的方法
implicit def String2Int(s:String) = s.toInt,结果又想将输入的Int参数转换为Double类型,又将Double类型转换为String类型,编译器将只会尝试最初定义的隐式转换方法
4. 显示操作现行原则。编译器发现代码类型并没有发生错误时,不会进行隐式转换操作。
5.最好将自己定义的隐式转换方法放到一个类中,使用时通过import,这样方便管理,复用性也比较强
【Scala】什么是隐式转换?它又能用来干嘛?该怎么用的更多相关文章
- Scala 中的隐式转换和隐式参数
隐式定义是指编译器为了修正类型错误而允许插入到程序中的定义. 举例: 正常情况下"120"/12显然会报错,因为 String 类并没有实现 / 这个方法,我们无法去决定 Stri ...
- scala高级性质-隐式转换 -02
今天我们来介绍scala的高级特性,上次已经介绍过他的一个特性:高阶函数,这次是隐式转换 1.隐式转换的例子 read的例子 解析:发现这个file没有read的方法,然后就开始在开始在这个上下文里面 ...
- Scala学习笔记--隐式转换
隐式转换的规则:1.无歧义规则:隐式转换唯有不存在其他可插入转换的前提下才能插入 若编译器有两种方法修正x+y 如convert1(x)+y,convert2(x)+y,会报错2.单一调用规则:只尝 ...
- Scala入门系列(十二):隐式转换
引言 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象.通过这些功能可以实现非常强大而且特殊的功 ...
- Scala 隐式转换及应用
什么是隐式转换 我们经常引入第三方库,但当我们想要扩展新功能的时候通常是很不方便的,因为我们不能直接修改其代码.scala提供了隐式转换机制和隐式参数帮我们解决诸如这样的问题. Scala中的隐式转换 ...
- Scala隐式转换
package big.data.analyse.scala import java.io.File import scala.io.Source /** * 隐式转换 * Created by zh ...
- Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、
1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...
- Spark记录-Scala程序例子(函数/List/match/option/泛型/隐式转换)
object func { def main(args:Array[String]):Unit={ //函数赋值给变量时, 必须在函数后面加上空格和下划线. def sayHello(name: St ...
- Scala学习之路 (八)Scala的隐式转换和隐式参数
一.概念 Scala 2.10引入了一种叫做隐式类的新特性.隐式类指的是用implicit关键字修饰的类.在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换. 隐式转换和隐式参数是Scal ...
- Scala隐式转换和隐式参数
隐式转换 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象或者是给一个类增加方法.通过这些功能, ...
随机推荐
- VCL安装有哪几种方法?
不是由Borland 提供的组件叫第三方组件: 就目前常见的各种形式的组件的安装方法介绍一下. 1.只有一个DCU文件的组件.DCU文件是编译好的单元文件,这样的组件是作者不想把源码公布.一般来说,作 ...
- codeforces Equalizing by Division (easy version)
output standard output The only difference between easy and hard versions is the number of elements ...
- C# WCF之用接口创建服务契约、部署及客户端连接
服务契约描述了暴露给外部的类型(接口或类).服务所支持的操作.使用的消息交换模式和消息的格式.每个WCF服务必须实现至少一个服务契约.使用服务契约必须要引用命名空间System.ServiceMode ...
- PHPSTORM快捷键On Mac
Command+Shift+O快捷定位文件,需要输入文件名称 Command+鼠标左键点击方法,快捷转到方法实现 Command+Option+方向左键,快捷返回上一步跳转方法之前 Shift+F6统 ...
- Linux 文件常用权限
-rw------- (600) 只有所有者才有读和写的权限 -rw-r--r-- (644) 只有所有者才有读和写的权限,组群和其他人只有读的权限 -rwx------ (700) 只有所有者才有读 ...
- 日志分析工具ELK(四)
Logstash收集TCP日志 #Input plugins TCP插件 所需的配置选项 tcp { port =>... } [root@linux-node1 ~]# cat tcp.con ...
- Spring5参考指南: SpEL
文章目录 Bean定义中的使用 求值 支持的功能 函数 Bean引用 If-Then-Else Elvis Safe Navigation 运算符 集合选择 集合投影 表达式模板化 SpEL的全称叫做 ...
- 【DNS域名解析命令】 dig
dig - DNS lookup utility dig 命令主要用来从 DNS 域名服务器查询主机地址信息. Dig (domain information groper 域名信息搜索)是一个灵活的 ...
- vuex-persist数据持久化存储插件
Vuex 解决了多视图之间的数据共享问题.但是运用过程中又带来了一个新的问题是,Vuex 的状态存储并不能持久化.也就是说当你存储在 Vuex 中的 store 里的数据,只要一刷新页面,数据就丢失了 ...
- 电子书下载:C# Database Basics
下载: http://download.csdn.net/detail/maxwoods/4089269