Scala implicit
Scala implicit
implicit基本含义
在Scala中有一个关键字是implicit
, 之前一直不知道这个货是干什么的,今天整理了一下。
我们先来看一个例子:
def display(input:String):Unit = println(input)
我们可以看到,display
函数的定义只是接受String
类型的入参,因此调用display("any string")
这样的函数是没问题的。但是如果调用display(1)
这样的入参不是String类型的话,编译会出错的。
如果我们想让display函数也能够支持Int类型的入参的话,除了我们重新定一个def display(input:Int):Unit = println(input)
这样的函数以外,我们还可以在相同的作用域内用implicit
关键字定义一个隐式转换函数,示例代码如下:
object ImplicitDemo {
def display(input:String):Unit = println(input)
implicit def typeConvertor(input:Int):String = input.toString
implicit def typeConvertor(input:Boolean):String = if(input) "true" else "false"
// implicit def booleanTypeConvertor(input:Boolean):String = if(input) "true" else "false"
def main(args: Array[String]): Unit = {
display("1212")
display(12)
display(true)
}
}
我们定义了2个隐式转换函数:
implicit def typeConvertor(input:Int):String = input.toString
implicit def typeConvertor(input:Boolean):String = if(input) "true" else "false"
这样display
函数就可以接受String、Int、Boolean类型的入参了。注意到上面我们的例子中注释的那一行,如果去掉注释的那一行的话,会在运行的时候出现二义性:
Error:(18, 13) type mismatch;
found : Boolean(true)
required: String
Note that implicit conversions are not applicable because they are ambiguous:
both method typeConvertor in object ImplicitDemo of type (input: Boolean)String
and method booleanTypeConvertor in object ImplicitDemo of type (input: Boolean)String
are possible conversion functions from Boolean(true) to String
display(true)
^
得出的结论是:
隐式转换函数是指在同一个作用域下面,一个给定输入类型并自动转换为指定返回类型的函数,这个函数和函数名字无关,和入参名字无关,只和入参类型以及返回类型有关。注意是同一个作用域。
implicit的应用
我们可以随便的打开scala函数的一些内置定义,比如我们最常用的map函数中->符号,看起来很像php等语言。
但实际上->确实是一个ArrowAssoc类的方法,它位于scala源码中的Predef.scala中。下面是这个类的定义:
final class ArrowAssoc[A](val __leftOfArrow: A) extends AnyVal {
// `__leftOfArrow` must be a public val to allow inlining. The val
// used to be called `x`, but now goes by `__leftOfArrow`, as that
// reduces the chances of a user's writing `foo.__leftOfArrow` and
// being confused why they get an ambiguous implicit conversion
// error. (`foo.x` used to produce this error since both
// any2Ensuring and any2ArrowAssoc pimped an `x` onto everything)
@deprecated("Use `__leftOfArrow` instead", "2.10.0")
def x = __leftOfArrow
@inline def -> [B](y: B): Tuple2[A, B] = Tuple2(__leftOfArrow, y)
def →[B](y: B): Tuple2[A, B] = ->(y)
}
@inline implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
我们看到def ->[B] (y :B)
返回的其实是一个Tuple2[A,B]
类型。
我们定义一个Map:
scala> val mp = Map(1->"game1",2->"game_2")
mp: scala.collection.immutable.Map[Int,String] = Map(1 -> game1, 2 -> game_2)
这里 1->"game1"
其实是1.->("game_1")
的简写。
这里怎么能让整数类型1能有->方法呢。
这里其实any2ArrowAssoc
隐式函数起作用了,这里接受的参数[A]是泛型的,所以int也不例外。
调用的是:将整型的1 implicit转换为 ArrowAssoc(1)
看下构造方法,将1当作__leftOfArrow
传入。
->方法的真正实现是生产一个Tuple2类型的对象(__leftOfArrow,y )
等价于(1, "game_id")
这就是一个典型的隐式转换应用。
其它还有很多类似的隐式转换,都在Predef.scala中:
例如:Int,Long,Double都是AnyVal的子类,这三个类型之间没有继承的关系,不能直接相互转换。
在Java里,我们声明Long的时候要在末尾加上一个L,来声明它是long。
但在scala里,我们不需要考虑那么多,只需要:
scala> val l:Long = 10
l: Long = 10
这就是implicit函数做到的,这也是scala类型推断的一部分,灵活,简洁。
其实这里调用是:
val l : Long = int2long(10)
更牛逼的功能
为现有的类库增加功能的一种方式,用java的话,只能用工具类或者继承的方式来实现,而在scala则还可以采用隐式转化的方式来实现。
隐式参数
看一个例子再说:
object ImplictDemo {
object Context{
implicit val ccc:String = "implicit"
}
object Param{
def print(content:String)(implicit prefix:String){
println(prefix+":"+content)
}
}
def main(args: Array[String]) {
Param.print("jack")("hello")
import Context._
Param.print("jack")
}
}
程序运行结果为:
hello:jack
implicit:jack
隐式转换扩展
import java.io.File
import scala.io.Source
class RichFile(val file:File){
def read = Source.fromFile(file.getPath()).mkString
}
object Context{
implicit def file2RichFile(f:File)= new RichFile(f)
}
object ImplictDemo {
def main(args: Array[String]) {
import Context.file2RichFile
println(new File("f:\\create.sql").read)
}
}
上面的代码中调用的read方法其实就是RichFile中定义的read方法。
最后的总结:
- 记住隐式转换函数的同一个scop中不能存在参数和返回值完全相同的2个implicit函数。
- 隐式转换函数只在意 输入类型,返回类型。
- 隐式转换是scala的语法灵活和简洁的重要组成部分
参考资料
Scala implicit的更多相关文章
- learning scala implicit class
隐式类可以用来扩展对象的功能非常方便 example: object ImplicitClass_Tutorial extends App { println("Step 1: How to ...
- Scala 隐式(implicit)详解
文章正文 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 1.Spark 中 ...
- scala 隐式详解(implicit关键字)
掌握implicit的用法是阅读spark源码的基础,也是学习scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...
- 转载:scala中的implicit
掌握implicit的用法是阅读Spark源码的基础,也是学习Scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...
- Beginning Scala study note(8) Scala Type System
1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...
- Scala比较器:Ordered与Ordering
在项目中,我们常常会遇到排序(或比较)需求,比如:对一个Person类 case class Person(name: String, age: Int) { override def toStrin ...
- A quick tour of JSON libraries in Scala
A quick tour of JSON libraries in Scala Update (18.11.2015): added spray-json-shapeless libraryUpdat ...
- 深入理解Scala的隐式转换系统
摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码. 使用方式: 1. ...
- 了解Scala反射
本篇文章主要让大家理解什么是Scala的反射, 以及反射的分类, 反射的一些术语概念和一些简单的反射例子. 什么是反射 我们知道, Scala是基于JVM的语言, Scala编译器会将Scala代码编 ...
随机推荐
- unix环境高级编程基础知识之第一篇
陆陆续续看完了圣经第一章,熟悉了unix的整个编程流程,c语言的用处在这里得到伸张. 从unix的体系结构,原来操作系统包括内核及一些其他软件,我们常常误称为linux内核为操作系统,这俨然成为一种共 ...
- 二:【nopcommerce系列】Nop的文件结构,引用关系。如何编译打包部署等
如果,你还没先看第一篇,先看看 一:[nopcommerce系列]Nop整体架构的简单介绍,在看nop代码之前,你需要懂哪些东西 如果你确定你已经看完了第一篇,并且真的理解 mvc.和autofac, ...
- C#中数组Array、ArrayList、泛型List<T>的比较
在C#中数组Array,ArrayList,泛型List都能够存储一组对象,但是在开发中根本不知道用哪个性能最高,下面我们慢慢分析分析. 一.数组Array 数组是一个存储相同类型元素的固定大小的顺序 ...
- iis7配置网站容易出现的问题(转)
来源: http://www.cnblogs.com/5426z/articles/4865022.html 1.64位操作系统 access数据库提示:未在本地计算机上注册"Microso ...
- JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法)
相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...
- Javascript/jQuery 获取地址栏URL参数的方法
1.jquery获取url很简单,代码如下 window.location.href; 2.javascript获取url参数 function getUrlParam(name) { var reg ...
- Spring学习进阶(四) Spring JDBC
Spring JDBC是Spring所提供的持久层技术.主要目的是降低使用JDBC API的门槛,以一种更直接,更简洁的方式使用JDBC API.在Spring JDBC里用户仅需要做哪些比不可少的事 ...
- Shell命令_if
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #if if [ 条件判断式 ] ...
- Entity Framework Code First (六)存储过程
声明:本文只针对 EF6+ 默认情况下,Code First 对实体进行插入.更新.删除操作是直接在表上进行的,从 EF6 开始你可以选择使用存储过程(Stored Procedures) 简单实体映 ...
- 素数筛 uva 543
给你一个n求出n由2个奇质因子的和 这2个因子差最大 没有就输出'Goldbach's conjecture is wrong. #include<stdio.h> #include&l ...