文档章节

Scala Implicit

任杰LL
 任杰LL
发布于 2017/05/19 18:18
字数 1339
阅读 25
收藏 0

序:前段时间用spray的时候对于http请求的参数以及response的结果用json格式的时候遇到了一个隐式转换,又专门查了一下加深下印象。温故知新果然又有收获,要记住这一句:隐式转换函数只在意 输入类型,返回类型。

我们经常在scala 源码里上看到类似implicit这个关键字。

一开始不太理解,后来看了看,发现implicit这个隐式转换是支撑scala的易用、容错以及灵活语法的基础。

我们经常使用的一些集合方法里面就用到了implicit,比如:

  def flatMap[S, That](f: T => GenTraversableOnce[S])(implicit bf: CanBuildFrom[Repr, S, That]): That = if (bf(repr).isCombiner) { ...... }

 

1. 隐式转换函数的定义:

我们在scala repl里定义一个方法foo,接受一个string的参数,打印出message

 当我们传入字符串参数"2"的时候,输出2

 但是当传入的类型是int而不是string的时候,出现类型不匹配异常。

 如果我们想支持隐式转换,将int转化为string,可以定义一个隐式函数,def implicit intToString( i : Int) = i.toString

 这里注意一下这个隐式函数的输入参数和返回值。

 输入参数:接受隐式转换入参为int类型

 返回值: 返回结果是string.

scala> def foo(msg : String) = println(msg)  
foo: (msg: String)Unit  
  
scala> foo("2")  
2  
  
scala> foo(3)  
<console>:9: error: type mismatch;  
 found   : Int(3)  
 required: String  
              foo(3)  
                  ^  
  
scala> implicit def intToString(i:Int) = i.toString  
warning: there were 1 feature warning(s); re-run with -feature for details  
intToString: (i: Int)String  
  
scala> foo(3)  
3  
scala> def bar(msg : String) = println("aslo can use implicit function intToString...result is "+msg)  
bar: (msg: String)Unit  
scala> bar(33)  
aslo can use implicit function intToString...result is 33  

总结一下,我的理解是:隐式函数是在一个scop下面,给定一种输入参数类型,自动转换为返回值类型的函数,和函数名,参数名无关。

这里intToString隐式函数是作用于一个scop的,这个scop在当前是一个scala repl,超出这个作用域,将不会起到隐式转换的效果。

为什么我会这么定义隐式函数,下面我再定义一个相同的输入类型为int,和返回值类型为string的隐式函数名为int2str:

scala> implicit def int2str(o :Int) = o.toString  
warning: there were 1 feature warning(s); re-run with -feature for details  
int2str: (o: Int)String  
  
scala> bar(33)  
<console>:13: error: type mismatch;  
 found   : Int(33)  
 required: String  
Note that implicit conversions are not applicable because they are ambiguous:  
 both method intToString of type (i: Int)String  
 and method int2str of type (o: Int)String  
 are possible conversion functions from Int(33) to String  
              bar(33)  
                  ^  


跑出了二义性的异常,说的是intToString和int2str这2个隐式函数都是可以处理bar(33)的,编译器不知道选择哪个了。证明了隐式函数和函数名,参数名无关,只和输入参数与返回值有关。

2. 隐式函数的应用

我们可以随便的打开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")的简写。理解这个原理之后,以前这么写Map的时候这个箭头的问题总是写错,这下再也不会写错了。

这里怎么能让整数类型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)

最后的总结:

1. 记住隐式转换函数的同一个scop中不能存在参数和返回值完全相同的2个implicit函数。

2. 隐式转换函数只在意 输入类型,返回类型。

3. 隐式转换是scala的语法灵活和简洁的重要组成部分。

本文转载自:http://blog.csdn.net/oopsoom/article/details/24643869

任杰LL
粉丝 3
博文 13
码字总数 9988
作品 0
信阳
私信 提问
Scala implicit implicit基本含义

Scala implicit implicit基本含义 在Scala中有一个关键字是implicit, 之前一直不知道这个货是干什么的,今天整理了一下。 我们先来看一个例子: def display(input:String):Unit = println...

泳泳啊泳泳
2018/01/07
0
0
Scala学习笔记(4):关于String

Scala并没有定义自己的String类型,而是直接借用了Java中的String,所以如果你定义一个String类型的值: val str = "hello" 返回的值的类型直接就是java.lang.String。然而,我们知道在Scala...

chengyao2
2013/05/14
0
0
Scala Implicit Parameters

Scala Implicit Parameters 如果定义函数时,标明某一参数为implicit,则这个参数是隐式参数。看起来与缺省参数(Default Parameters)类似,调用者不必在调用时指定该参数。 但是就实际运行...

秋风醉了
2015/04/28
0
0
Spark算子:RDD行动Action操作(2)–take、top、takeOrdered

take def take(num: Int): Array[T] take用于获取RDD中从0到num-1下标的元素,不排序。 scala> var rdd1 = sc.makeRDD(Seq(10, 4, 2, 12, 3)) rdd1: org.apache.spark.rdd.RDD[Int] = Paral......

chensanti234
2016/12/20
5
0
scala 果然是一门非常有创造力的语言

Scala作为JVM上的新语言,借鉴了OO和FP的很多思想,推荐各位有时间可以看看。FP的很多思想对于习惯了OO的人来说简直是一种冲击。 我特别喜欢Scala无处不在的Pattern Match,以及implicit的概...

xiaowenliang
2010/12/10
2.5K
8

没有更多内容

加载失败,请刷新页面

加载更多

宜信开源|一个实例解析PaaS平台LAIN的9大杀手级功能

一、基于Docker的PaaS平台LAIN 在金融的场景下,LAIN 是为解放各个团队和业务线的生产力而设计的一个云平台。LAIN 正式上线已经大约两年,基本已经成熟,为宜信大数据创新中心各个团队提供了...

宜信技术学院
19分钟前
3
0
DBeaver调整编辑窗口字体大小

窗口-->首选项: 点击“编辑”之后,字体大小设为11的大小即比较合适。

BG2KNT
25分钟前
2
0
【Kubernetes社区之路】Slack沟通工具简介

什么是Slack Slack(https://slack.com) 是一款沟通工具,它与国内常见的微信、微博、QQ、钉钉有很大的不同,Slack主要用于工作讨论,可以让讨论更加高效。 Slack的口号便是让工作变得简单、...

恋恋美食
37分钟前
2
0
Visual Paradigm 教程[UML]:如何在SoaML中建模多方服务?

下载Visual Paradigm最新试用版 编写本教程是为了解释多方服务在SoaML方面的含义以及如何使用各种SoaML图表指定此类服务Visual Paradigm。 本教程中将使用的示例是通过在线银行账户纳税。您将...

xiaochuachua
38分钟前
0
0
SpringMVC 的Controller方法声明为private 或者 public 有什么区别

平常没有区别,都能正常处理请求。只有在使用AOP时会有问题: Controller方法声明为private时会出现获取到的注入service属性为null的问题,public方法才能正常获取注入的service。 原因如下:...

为了美好的明天
40分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部