Scala之隐式转换「建议收藏」

Scala之隐式转换「建议收藏」概述简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。隐式转换有四种常见的使用场景:将某一类型转换成预期类型类型增强与扩展模拟新的语法类型类语法隐式转换有新旧两种定义方法,旧的定义方法指是的“implictdef”形式,这是Scala2.10版本之前的写法,在Scala2.10版本之

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

推荐:博主历时三年倾注大量心血创作的《大数据平台架构与原型实现:数据中台建设实战》一书已由知名IT图书品牌电子工业出版社博文视点出版发行,真诚推荐给每一位读者!点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,扫码进入京东手机购书页面!

在这里插入图片描述

 

 

概述

简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。本文原文出处: http://blog.csdn.net/bluishglc/article/details/50866314 严禁任何形式的转载,否则将委托CSDN官方维护权益!

隐式转换有四种常见的使用场景:

  1. 将某一类型转换成预期类型
  2. 类型增强与扩展
  3. 模拟新的语法
  4. 类型类

语法

隐式转换有新旧两种定义方法,旧的定义方法指是的“implict def”形式,这是Scala 2.10版本之前的写法,在Scala 2.10版本之后,Scala推出了“隐式类”用来替换旧的隐式转换语法,因为“隐式类”是一种更加安全的方式,对被转换的类型来说,它的作用域更加清晰可控。

接下来我们通过实例来了解这两种隐式转换的写法。前文提到,隐式转换最为基本的使用场景是:将某一类型转换成预期类型,所以我们下面的例子就以最这种最简单的场景来演示,它们都实现了:将一个String类型的变量隐式转换为Int类型:

“implict def”形式的隐式转换

package com.github.scala.myimplicit

/**
  * A demo about scala implicit type conversion.
  * @author Laurence Geng
  */
object ImplicitDefDemo {

    object MyImplicitTypeConversion {
        implicit def strToInt(str: String) = str.toInt
    }

    def main(args: Array[String]) {
        //compile error!
        //val max = math.max("1", 2);
        import MyImplicitTypeConversion.strToInt
        val max = math.max("1", 2);
        println(max)
    }
}

“隐式类”形式的隐式转换

package com.github.scala.myimplicit

/**
  * A demo about scala implicit type conversion.
  * @author Laurence Geng
  */
object ImplicitClassDemo {

    implicit class MyImplicitTypeConversion(val str: String){
         def strToInt = str.toInt
    }

    def main(args: Array[String]) {
        //compile error!
        //val max = math.max("1", 2);
        import com.github.scala.myimplicit.ImplicitDefDemo.MyImplicitTypeConversion._
        val max = math.max("1", 2);
        println(max)
    }
}

隐式类有如下几个限制:

  1. They must be defined inside of another trait/class/object.

  2. They may only take one non-implicit argument in their constructor.

  3. There may not be any method, member or object in scope with the same name as the implicit class.
    Note: This means an implicit class cannot be a case class.

隐式类与旧的隐式转换的语法(implicit def)是有细微的不同的,隐式类的运作方式是:隐式类的主构造函数只能有一个参数(有两个以上并不会报错,但是这个隐式类永远不会被编译器作为隐式类在隐式转化中使用),且这个参数的类型就是将要被转换的目标类型。从语义上这很自然:这个隐式转换类将包裹目标类型,隐式类的所有方法都会自动“附加”到目标类型上。

应用场景

转换成预期类型

对于这种使用场景实际上并不多见,实际意义也没有那么大。前文的代码就是这样这一场景的一个示例。

类型增强与扩展

真正让隐式转换大放异彩的是“类型增强”。这方面的示例是非常多的。

案例一:ArrayOps对Array的类型增强

一个典型案例是:Scala对Array对象进行的隐式转换。我们知道,Scala通过Predef声明了针对Array类型的两个隐式转换:一个是到ArrayOps的隐式转化,另一个是到WrappedArray的隐式转换。以前者为例,它为Array对象“添加”了大量的操作,这是通过隐式转换来”通明“的对一个类进行增强的典型案例!以下是Scala API文档中对这一技术细节的说明:

Two implicit conversions exist in scala.Predef that are frequently applied to arrays: a conversion to scala.collection.mutable.ArrayOps (shown on line 4 of the example above) and a conversion to scala.collection.mutable.WrappedArray (a subtype of scala.collection.Seq). Both types make available many of the standard operations found in the Scala collections API. The conversion to ArrayOps is temporary, as all operations defined on ArrayOps return an Array, while the conversion to WrappedArray is permanent as all operations return a WrappedArray.

###案例二:Spark中PairRDDFunctions对RDD的类型增强

如果你看一下Spark中的RDD以及它的子类是没有groupByKey, reduceByKey以及join这一类基于key-value元组的操作的,但是在你使用RDD时,这些操作是实实在在存在的,Spark正是通过隐式转换将一个RDD转换成了PairRDDFunctions, 这个动作是这样发生的:

首先在RDD的伴随对象中声明了从RDD到PairRDDFunctions的隐式转换:

Scala之隐式转换「建议收藏」

然后在SparkContext中import了RDD的所有东西,使隐式转换生效。

模拟新的语法

这也是非常酷的一种应用场景。一个典型的应用场景就是Map中用于创建key-value元组的->符号,它就是一个隐式转换的产物。->不是 scala 本身的语法,而是类型 ArrowAssoc 的一个方法。这个类型定义在包 Scala.Predef 对象中。 Scala.Predef 自动引入到当前作用域,在这个对象中,同时定义了一个从类型 Any 到 ArrowAssoc 的隐含转换。因此当使用 1 -> “One”时,编译器自动插入从 1 转换到 ArrowAsso c转换。

Scala之隐式转换「建议收藏」

类型类

类型类是一种非常灵活的设计模式,可以把类型的定义和行为进行分离,让扩展类行为变得非常方便。或者说如果我们想创建跨越类型的功能(即功能实现独立于类型去演变),那么这样的“功能”不是适合也不应该在主类型的层次结构上进行演变的,这时是使用类型类的绝佳场所。因为类型类是一个比较独立的语法,虽然它的实现需要使用到类型类,但是在本文中为了不止于失去焦点,我们不打算在这里详细介绍,而在接下来的一篇文章中进行专门的介绍。

隐式解析的搜索范围

这一部分的规则有些复杂,根据《Scala In Depth》所描述的,顶层的搜索逻辑是:

  • 在当前作用域下查找。这种情形又分两种情况,一个是在当前作用域显示声明的implicit元素,另一个通过import导入的implicit元素。
  • 如果第一种方式没有找到,则编译器会继续在隐式参数类型的隐式作用域里查找。

真正复杂的地方是什么叫一个类型的隐式作用域?一个类型的隐式作用域指的是“与该类型相关联的类型”的所有的伴生对象

OK,那什么叫作“与一个类型相关联的类型”? 定义如下:

  • 假如T是这样定义的:T with A with B with C,那么A, B, C的伴生对象都是T的搜索区域。
  • 如果T是类型参数,那么参数类型和基础类型都是T的搜索部分。比如对于类型List[Foo],List和Foo都是搜索区域
  • 如果T是一个单例类型p.T,那么p和T都是搜索区域
  • 如果T是类型注入p#T,那么p和T都是搜索区域。

隐式参数

为什么把隐式参数单独拿出来放到最后讲是因为从用意上讲,隐式参数与我们前面讲述的隐式类型转化有很大的差异,虽然它涉及到了关键字implict,但是它做的是另外一件事情。隐含参数有点类似缺省参数,如果在调用方法时没有提供某个参数,编译器会在当前作用域查找是否有符合条件的 implicit 对象可以作为参数传入,不同于缺省参数,隐式参数的值可以在方法调用的前的上下文中指定,这是隐式参数更加灵活的地方。

object ImplicitParamDemo { 
   

    object Greeter{ 
   
        def greet(name:String)(implicit prompt: String) { 
   
            println("Welcome, " + name + ". The System is ready.")
            println(prompt)
        }
    }

    def main(args: Array[String]) { 
   

        implicit val prompt = ">"

        Greeter.greet("admin")
    }

}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183083.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 这11款chrome神器,用起来爽到爆

    这11款chrome神器,用起来爽到爆前言对于从事IT行业的我们来说,几乎无时无刻都在用chrome浏览器,因为它给我们的工作和生活带来了极大的便利。今天给大家分享我用过的11款牛逼的chrome插件,你看完前3个可能就会忍不住想点赞了。1.谷歌翻译很多小伙伴,英语不太好,包括我自己,英语刚过四级。从事软件相关工作时,有时有些吃力,因为很多优秀的技术网站、书籍或者文章都是老外写的,如果因为看不懂就放弃阅读,我们将会少了很多学习和进步的机会。今天分享的第一个神器就是:谷歌翻译。在没使用谷歌翻译之前,访问https://doc

    2022年5月6日
    52
  • eclipse安装教程(2021最新版)超级易懂到吐血

    eclipse安装教程(2021最新版)超级易懂到吐血第一步:下载JDK(下载地址)http://www.oracle.com/technetwork/java/javase/downloads/index.html第二步根据自己电脑的系统,选择相应的版本x64代表64位,x86代表32位。点击相应的JDK进行下载点击之后会出现一个对话框同意之后下载。(记住下载到哪,打开之后一路同意安装即可)记住你把JDK安装到哪里,文件路径不要有中文,不然会无法识别,我安装的时候把JDK装到了F盘第三步:配置环境变量这里解释一下什么是环境.

    2022年6月14日
    43
  • SO库版本号管理

    SO库版本号管理编写SO库文件时可以输入版本号调用SO库文件中特定的函数可以输出版本号

    2022年6月17日
    46
  • github 项目地址

    github 项目地址AutoSize:implementation’me.jessyan:autosize:1.2.1’2021/01/22https://github.com/JessYanCoding/AndroidAutoSize

    2022年7月16日
    20
  • 四位数除以两位数的除法算式_4整除2

    四位数除以两位数的除法算式_4整除2原题链接这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 ——

    2022年8月8日
    12
  • 安装 | 最新MATLAB 2020b(64位)安装教程完整版[通俗易懂]

    安装 | 最新MATLAB 2020b(64位)安装教程完整版[通俗易懂]博主github:https://github.com/MichaelBeechan博主CSDN:https://blog.csdn.net/u011344545精简安装链接:https://blog.csdn.net/u011344545/article/details/109728674下载链接链接:https://pan.baidu.com/s/1g61g2qJO2MtZVkeMsuxhuQ提取码:打赏连接:https://blog.csdn.net/u011344545/article/

    2022年5月10日
    64

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号