scala的隐式转换学习总结(详细)
一,隐式转换函数
1, 格式,
implicit def 函数名(参数):返回值类型={
//函数体
//返回值
}
2,例子:
//导入对应的规则类,以免出现警告
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
//定义将Int类型的值转换为Float的函数
scala> implicit def int2float(x:Int): Float = x.toFloat
int2float: (x: Int)Float scala> val x:Float = 2
x: Float = 2.0
scala>
3,注意事项:
1) 隐式转换函数的函数名可以是任意的,与函数名称无关,只与函数签名(函数参数和返回值类型)有关。
2)如果当前作用域中存在函数签名相同但函数名称不同的两个隐式转换函数,则在进行隐式转换时会报错。
//函数一
scala> implicit def int2float2(x: Float): Int = x.toInt
int2float2: (x: Float)Int
//函数二
scala> implicit def int2float(x: Float): Int = x.toInt
int2float: (x: Float)Int
//调用,报错
scala> val x:Int = 2.55f
<console>:14: error: type mismatch;
found : Float(2.55)
required: Int
Note that implicit conversions are not applicable because they are ambiguous:
both method int2float2 of type (x: Float)Int
and method int2float of type (x: Float)Int
are possible conversion functions from Float(2.55) to Int
val x:Int = 2.55f
^
二,隐式类与隐式对象
1,隐式类:通过在类名前使用 implicit 关键字定义
1)格式:
implicit class 类名(参数){
//类主体
}
例子:string中没有bark方法,通过隐式转换,调用对应的方法转换
scala> implicit class Dog(val name: String){
| def bark=println(s"$name is barking")}
defined class Dog
scala> "barkdo".bark
barkdo is barking
2)注意事项: 隐式类的主构造函数参数有且仅有一个!之所以只能有一个参数,是因为隐式转换是将一种类型转换为另外一种类型,源类型与目标类型是一一对应的
scala> implicit class Dog2(val name: String, val age: Int){
| def bark=println(s"$name is barking")}
<console>:15: error: implicit classes must accept exactly one primary constructor parameter
implicit class Dog2(val name: String, val age: Int){
2 隐式对象
格式:
implicit object 对象名{
//类主体
}
例子
object ImplicitTest extends App{
//定义一个trait Multiplicable
trait Multiplicable[T]{
def multiply(x: T):T
}
//定义一个隐式对象,用于整型数据相乘
implicit object MultiplicableInt extends Multiplicable[Int]{
def multiply(x: Int): Int = x*x
}
//定义一个用于字符串相乘的隐式对象
implicit object MultiplicableString extends Multiplicable[String]{
def multiply(x: String): String = x*2
}
//定义一个函数,函数具有泛型参数
def multiply[T: Multiplicable](x: T): T ={
//implicitly方法,访问隐式对象
val ev = implicitly[Multiplicable[T]]
//根据具体的类型调用相应的隐式对象中的方法
ev.multiply(x)
}
//调用隐式对象 MultiplicableInt 中的方法
println(multiply(5))
//调用隐式对象 MultiplicableString 中的方法
println(multiply("5"))
}
运行结果: 25 55
三,隐式参数与隐式值
1, 隐式参数,在函数的定义时,在参数前添加implicit关键字。
格式:
def 函数名(implicit 参数名:l类型):返回值={
//函数体
}
例子://修改上面的一个方法
//定义一个函数,函数具有泛型参数
def multiply[T: Multiplicable](x: T)(implicit ev: Multiplicable[T]): T ={
//根据具体的类型调用相应的隐式对象中的方法
ev.multiply(x)
}
2)隐式值:
格式
implicit val 变量名:类型=值
例子
//定义一个带隐式参数的函数
scala> def sqrt(implicit x: Double) = Math.sqrt(x)
sqrt: (implicit x: Double)Double
//定义一个隐式值
scala> implicit val x:Double = 2.55
x: Double = 2.55
//调用定义的sqrt函数,它将自行调用定义好的隐式值
scala> sqrt
res1: Double = 1.5968719422671311
3,隐式参数使用的常见问题:
1)当函数没有柯里化时,implicit关键字会作用于函数列表中的的所有参数。
2)隐式参数使用时要么全部不指定,要么全不指定,不能只指定部分。
3)同类型的隐式值只能在作用域内出现一次,即不能在同一个作用域中定义多个相同类型的隐式值。
4)在指定隐式参数时,implicit 关键字只能出现在参数开头。
5)如果想要实现参数的部分隐式参数,只能使用函数的柯里化,
如要实现这种形式的函数,def test(x:Int, implicit y: Double)的形式,必须使用柯里化实现:def test(x: Int)(implicit y: Double).
6) 柯里化的函数, implicit 关键字只能作用于最后一个参数。否则,不合法。
7)implicit 关键字在隐式参数中只能出现一次,柯里化的函数也不例外!
scala> def product(implicit x: Double, implicit y: Double)=x*y
<console>:1: error: identifier expected but 'implicit' found.
def product(implicit x: Double, implicit y: Double)=x*y
scala> def product(implicit x: Double)(implicit y: Double)=x*y //柯里化函数
<console>:1: error: '=' expected but '(' found.
def product(implicit x: Double)(implicit y: Double)=x*y
8)匿名函数不能使用隐式参数
scala> val prodeuct = (x: Double, y: Double) => x*y
prodeuct: (Double, Double) => Double = <function2> scala> val prodeuct = (implicit x: Double, y: Double) => x*y
<console>:1: error: '=>' expected but ',' found.
val prodeuct = (implicit x: Double, y: Double) => x*y
^
9)柯里化的函数如果有隐式参数,则不能使用其偏应用函数
//柯里化函数product
scala> def product(x: Double)(y: Double)=x*y
product: (x: Double)(y: Double)Double
//两个参数的偏应用函数
scala> val p1=product _
p1: Double => (Double => Double) = <function1>
//调用
scala> p1(3.0)(4.0)
res1: Double = 12.0
//一个参数的偏应用函数
scala> val p2 = product(3.0) _
p2: Double => Double = <function1>
//调用
scala> p2(4.0)
res2: Double = 12.0
//将柯里化函数参数y, 声明为隐式参数
scala> def product(x: Double)(implicit y: Double)=x*y
product: (x: Double)(implicit y: Double)Double
//定义隐式参数后,便不能使用其偏应用函数
scala> val p1=product _
<console>:13: error: could not find implicit value for parameter y: Double
val p1=product _
^
scala>
四,隐式函数的若干规则:
1)显示定义规则
在使用带有隐式参数的函数时,如果没有明确指定与参数类型匹配相同的隐式值,编译器不会通过额外的隐式转换来确定函数的要求。
2)作用域规则
不管是隐式值,隐式对象,隐式类或隐式转换函数,都必须在当前的作用域使用才能起作用!
3)无歧义规则
所谓无歧义值的是,不能存在多个隐式转换是代码合法,如代码中不应该存在两个隐式转换函数能够同时使某一类型转换为另一类型,也不应该存在相同的两个隐式值,主构造函数参数类型以及成员方法等同的两个隐式类。
4)一次性转换规则
隐式转换从源类型到目标类型只会经过一次转换,不会经过多次隐式转换达到。
scala的隐式转换学习总结(详细)的更多相关文章
- scala自定义隐式转换
Scala自定义隐式转换 一.编写隐式转换类 /** * Author Mr. Guo * Create 2019/4/20 - 17:40 */ object StringImprovments { ...
- Scala学习之路 (八)Scala的隐式转换和隐式参数
一.概念 Scala 2.10引入了一种叫做隐式类的新特性.隐式类指的是用implicit关键字修饰的类.在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换. 隐式转换和隐式参数是Scal ...
- Scala之隐式转换
概述 简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型. 隐式转换有四种常见的使用场景: 将某一类 ...
- 深入理解Scala的隐式转换系统
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- Scala模式匹配| 隐式转换
1. 模式匹配 Scala中的模式匹配类似于Java中的switch语法,但是更加强大.模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分 ...
- 转载:深入理解Scala的隐式转换系统
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- Scala之隐式转换implicit详解
假设我们有一个表示文本的行数的类LineNumber: class LineNumber ( val num : Int ) 我们可以用这个类来表示一本书中每一页的行数: val lineNumOfP ...
- 深入理解Scala的隐式转换
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- scala的隐式转换
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
随机推荐
- LVS之2---基于LVS负载均衡集群架构
LVS之2---基于LVS负载均衡集群架构实现 目录 LVS之2---基于LVS负载均衡集群架构实现 ipvsadm software package Options 常用命令 保存及重载规则 内存映 ...
- 第十六章节 BJROBOT 开机自启动服务【ROS全开源阿克曼转向智能网联无人驾驶车】
1.把小车平放在地板上,用资料里的虚拟机,打开一个终端 ssh 过去主控端运行rosrun robot_upstart install znjrobot/launch/bringup.launch 2 ...
- 单细胞分析实录(5): Seurat标准流程
前面我们已经学习了单细胞转录组分析的:使用Cell Ranger得到表达矩阵和doublet检测,今天我们开始Seurat标准流程的学习.这一部分的内容,网上有很多帖子,基本上都是把Seurat官网P ...
- hive 将hive表数据查询出来转为json对象和json数组输出
一.将hive表数据查询出来转为json对象输出 1.将查询出来的数据转为一行一行,并指定分割符的数据 2.使用UDF函数,将每一行数据作为string传入UDF函数中转换为json再返回 1.准备数 ...
- 漫画|web的主要安全问题
在此主要说现在市面上存在的4个比较多的安全问题 一.钓鱼 钓鱼: 比较有诱惑性的标题 仿冒真实网站 骗取用户账号 骗取用户资料 二.篡改页面 有一大部分被黑的网站中会有关键字 (在被黑的网站中,用的最 ...
- SpringCloud | 通过电商业务场景让你彻底明白SpringCloud核心组件的底层原理
本文分为两个部分: Spring Cloud"全家桶"简单介绍. 通过实际电商业务场景,让你彻底明白Spring Cloud几个核心组件的底层原理. Spring Cloud介绍 ...
- Cocos Creator 新资源管理系统剖析
目录 1.资源与构建 1.1 creator资源文件基础 1.2 资源构建 1.2.1 图片.图集.自动图集 1.2.2 Prefab与场景 1.2.3 资源文件合并规则 2. 理解与使用 Asset ...
- WPF + RDLC + 动态生成列 + 表头合并
如下,评论超过20条,马上发代码*(੭*ˊᵕˋ)੭*ଘ,效果如下: 代码逻辑简单. WPF使用RDLC需要使用如下DLL 新建WPF 窗体,黏贴下大概如下 <Window xmlns:rv=&q ...
- 真的,kafka 入门看这一篇准没错!
什么是 Kafka Kafka 是一个分布式流式平台,它有三个关键能力 订阅发布记录流,它类似于企业中的消息队列 或 企业消息传递系统 以容错的方式存储记录流 实时记录流 Kafka 的应用 作为消息 ...
- go跳出多层循环的几种方式
前言 比如这样的需求, 遍历一个 切片, 切片内容是切片1, 需求是判断切片1中某个是否有相应数据, 有就返回 正文 我们需要考虑的是在写两层遍历时如何在获取结果后结束这两层遍历 变量法 设置一个变量 ...