scala隐式转换(隐式函数、隐式值、隐式类)implicit

目录

隐式转换的目的:

隐式转换的时机:

一、隐式函数

实例1:隐式函数类型转换

实例2:隐式函数 & 类结合使用

二、隐式变量(隐式值)& 隐式参数

三、隐式类

实例:与 隐式函数 & 类结合使用的对比

四、隐式转换机制


隐式转换的目的:

通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码。

 

隐式转换的时机:

(1)当方法中的参数的类型与目标类型不一致时

(2)当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换(根据类型)

 

一、隐式函数

implicit def 函数名(参数:参数类型):返回值类型={
       函数体
       返回值
}

当main方法中,某个变量类型A => 返回值类型B,编译器会自动寻找隐式函数(参数类型A、返回值类型B)进行转换,并且返回值是通过隐式函数函数体计算得出结果

(1)编译器只关注隐式函数的函数签名(参数类型和返回值类型),与函数名无关

(2)隐式函数只能有一个参数

(3)同一个作用域内不能存在两个相同函数签名的隐式函数,否则会报错,因为表达式不知道调用哪个隐式函数


实例1:隐式函数类型转换

·  e是一个s类型的表达式,需要的是T类型,编译器就会寻找S => T的隐式函数,自动转换

object ImplicitDemo1 {
    def main(args: Array[String]): Unit = {
        //隐式函数
        implicit def imp(d:Double):Int={
            d.toInt
        }
        var a:Int = 3.9
        println(a)
    }
}

---------
3

变量a,传入值是Double类型,返回Int类型;自动寻找隐式函数imp,调用函数体 3.9.toInt,最后返回Int类型的a是3;打印结果3

实例2:隐式函数 & 类结合使用

·  e是一个S类型的表达式,使用点号访问e.m时,m不是类型S的成员而类A的成员,那么编译器会寻找隐式函数(S => A),自动转换,使e.m合法

//要求 x days ago,返回x天前的日期;
//x days future,返回x天后的日期

object ImplicitDemo3 {
    def main(args: Array[String]): Unit = {
        implicit def int2DateHelper(num: Int): DateHelper = new DateHelper(num)

        println(2 days "ago")
        println(3 days "future")
    }
}

class DateHelper(var num: Int) {
    var today = LocalDate.now()
    def days(when: String): LocalDate = {
        if (when == "ago") today.minusDays(num)
        else today.plusDays(num)
    }
}
---------------
2019-01-07
2019-01-15

思路:

写一个days方法,x(Int),x.days("ago")时,计算当前时间x天前的日期;x.days("future")时,计算当天时间x天后的日期

x是基本数据类型Int,不能直接调用方法;所以需要把Int => 类,类中有days方法

所以需要1. 写一个类,里面有days方法;  2. 隐式函数,把Int(参数类型) => 类(返回值类型)。

 

二、隐式变量(隐式值)& 隐式参数

(1)隐式变量

implicit 修饰符 参数名:参数类型 = 默认值

(2)隐式参数

def 函数名(implicit 参数名:参数类型):返回值类型 = {
        函数体
        返回值
}

函数中给参数加上implicit,表明这是隐式参数,在调用该函数时,可以不用传递隐式参数,直接用函数名

编译器会寻找一个被implicit标记过的隐式变量,隐式变量的参数类型,与隐式参数的类型一致,可以直接调用隐式变量作为隐式参数

object ImplicitDemo4 {
    def main(args: Array[String]): Unit = {
        say("kevin")
        say
    }

    //隐式参数
    def say(implicit name: String) = {
        val str: String = name + "你好..."
        println(str)
    }

    //隐式变量
    implicit var name1: String = "name1"
}

--------------
kevin你好...
name1你好...

可见,隐式变量自动引入隐式参数时,与变量名无关,只匹配变量类型;当函数没有参数时,直接调用同类型的隐式变量作为隐式参数传入def say函数进行运算。

ps:隐式值的优先级高于默认值

 

三、隐式类

隐式类用于扩展已存在的类;用法等价于之前的隐式函数和类结合使用,写法更简洁

 -> 隐式函数 & 类结合使用:

先构造类写方法体;再创建隐式函数,返回值就是new 类对象,隐式函数与返回值的形参列表一致;再用隐式函数去转换

 -> 隐式类:创建隐式类,再用隐式类去new对象;直接转换。

核心:符合隐式类形参列表中参数类型的变量,都可以调用隐式类中的方法

implicit class 类名(修饰符 参数:参数类型){
        //类主体
}

隐式类的特点:

(1)构造参数有且只有一个

(2)隐式类必须定义在类、伴生对象、包对象里,即隐式类不能是顶级的

(3)作用域内不能有与之相同名称的标识符

(4)implicit关键词不能用于case类

实例:与 隐式函数 & 类结合使用的对比

//要求 x days ago,返回x天前的日期;
//x days future,返回x天后的日期

object ImplicitClass1 {
    implicit class DateHelper(val num : Int){
        val today = LocalDate.now()
        def days(when:String)={
            if(when == "ago") today.minusDays(num)
            else today.plusDays(num)
        }
    }

    def main(args: Array[String]): Unit = {
        println(2 days "ago")
        println(4 days "future")
    }
}

---------------
2019-01-08
2019-01-14

与一种隐式函数 & 类的写法对比,简化了创建隐式函数的步骤,代码更简洁

 

四、隐式转换机制

即编译器是如何查找到缺失信息的,解析具有以下两种规则:

1 .首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象) 
2. 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:

(1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索

(2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的 
伴生对象和String的伴生对象

(3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索

(4) 如果T是个类型注入S#T,那么S和T都会被搜索

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值