文档章节

隐式转换 implicit

c
 chensanti234
发布于 2017/05/07 21:45
字数 1256
阅读 11
收藏 0

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方法。

最后的总结:

  1. 记住隐式转换函数的同一个scop中不能存在参数和返回值完全相同的2个implicit函数。
  2. 隐式转换函数只在意 输入类型,返回类型。
  3. 隐式转换是scala的语法灵活和简洁的重要组成部分

参考资料

本文转载自:http://www.cnblogs.com/rollenholt/p/4118567.html

下一篇: 创建SBT工程
c
粉丝 0
博文 35
码字总数 9512
作品 0
深圳
私信 提问
对Scala隐式转换的一些总结

以下讨论基于Scala 2.7/2.8 Scala提供的隐式转换特性可以在效果上给一个类增加一些方法,或者用于接收不同类型的对象,然而使用Scala的隐式转换是有一定的限制的,总结如下 implicit关键字只...

ggd543archer
2018/07/28
0
0
scala implicit 关键字

implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把最后一个参数列表标记为implicit,表示该组参数是隐式参数。一个方法只会有一个隐式参数列表,...

张欢19933
2018/04/27
0
0
Scala Implicit Parameters

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

秋风醉了
2015/04/28
0
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

没有更多内容

加载失败,请刷新页面

加载更多

Django笔记-3-模型-20190526

简介 django为各种数据库提供了很好的支持,django对这些数据库提供了统一的调用API;可以根据不同的也无需求选择不同的数据库; 配置数据库 在setting.py文件中配置数据库 DATABASES = { ...

Frank1126lin
21分钟前
0
0
OSChina 周日乱弹 —— 程序员做噩梦

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# 手嶌葵《Kiss The Girl》 《Kiss The Girl》- 手嶌葵 手机党少年们想听歌,请使劲儿戳(这里) @Sharon啊 :今天...

小小编辑
55分钟前
123
9
Another app is currently holding the yum lock; waiting for it to exit...

Another app is currently holding the yum lock; waiting for it to exit... The other application is: PackageKit Memory : 153 M RSS (266 MB VSZ) Started: Thu Jul 12 00:03......

圣洁之子
今天
2
0
FastDateFormat 研究

FastDateFormat 对缓存的利用,其实就是用ConcurrentHashMap 做了一个map类型的缓存 public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { Validate......

暗中观察
今天
3
0
Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部