美文网首页
Kotlin:扩展函数和运算符重载和infix函数

Kotlin:扩展函数和运算符重载和infix函数

作者: jingkaiqaq | 来源:发表于2021-05-28 15:19 被阅读0次
    kotlin&android.png

    前言

    兄弟们好,经过前边三篇知识的学习及掌握,相信对于Kotlin代码已经比较熟悉了,相信我输出内容一定会帮助到各位大佬
    😬😬😬😬😬😬😬😬😬😬
    下面有请各位大佬观看通俗易懂Kotlin系列之第四篇文章——扩展函数和运算符重载、infix函数
    发车了兄弟们GO GO GO ~ (滑稽)

    1:扩展函数

    首先我们需要了解什么是扩展函数,扩展函数就是在不修改某个类源码的情况下,可以打开这个类,并且向该类添加新的函数
    啥?向一个类添加新的函数,并不修改源码? 身为java出生的android码畜你一定没有听过如此滑稽的事情,下边我们一起来看一下到底如何实现的
    我们先来实现一个功能:一段字符串中可能包含数字、字母和特殊符号等字符,现在我们希望统计字符串中字母的数量,实现功能的代码如下:

    object StringUtils {
        fun lettersCount(str: String): Int {
            var count = 0
            for (char in str) {
                if (char.isLetter()) {
                    count++
                }
            }
            return count
        }
    }
    

    上边的代码是我们用传统的代码实现 接下来我们看一下如何使用扩展函数的方式将lettersCount()添加到String类当中实现
    下边是定义扩展函数的语法:

    fun ClassName.MethodName(param1:Int,param2:Int):Int{
      return 0
    }
    

    相对于一个普通函数,定义扩展函数,只需要在函数名的前面加上一个ClassName.的语法结构,就表示将该函数定义到指定类当中了
    下边我们尝试想String类中添加一个扩展函数
    首先创建一个Kotlin.kt文件 请注意之前的文章强调过 .kt也就是新建File文件主要是用来创建扩展函数和顶层函数
    一般的我们建议需要向哪个类中添加扩展函数就新建这个类的.kt文件,当然扩展函数也可以定义在现有的类中,不一定要新建file文件,但是最好定义成顶层函数,这样就可以全局使用 。String代码如下:

    fun String.lettersCount(): Int {
        var count = 0
        for (char in this) {
            if (char.isLetter()) {
                count++
            }
        }
        return count
    }
    

    注意这里我们将lettersCount定义成了String类的扩展函数,这样的话整代码就有了String类的上下文
    调用的地方如下:

        val count = "hfdah*(……123df".lettersCount()
    

    Kotlin的扩展函数可以让你的代码更加简洁、丰富、更加面向对象,另外Kotlin有reverse()函数
    用于反转字符串,capitalize()函数用于对首字母进行大写等,这些都是Kotlin自带的扩展函数,你可以向任何类中添加扩展函数来提升你开发效率(提升开发效率?开玩笑,当然是为了装13啦😜)...

    另外我们也可以使用扩展函数简化Toast的使用
    下边是toast函数具体使用方法

    Toast.makeText(context, "This is Toast", Toast.LENGTH_SHORT).show()
    

    我们新建一个Toast.kt文件

    fun String.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) {
     Toast.makeText(context, this, duration).show()
    }
    fun Int.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) {
     Toast.makeText(context, this, duration).show()
    }
    

    调用只需要:

    "This is Toast".showToast(context, Toast.LENGTH_LONG)
    

    2:运算符重载

    java中有许多语言内置运算符,比如:+-*/%等
    Kotlin允许我们将所有的运算符甚至其他关键字进行重载,从而拓展这些运算符和关键字的用法
    Kotlin运算符重载允许任意的对象进行运算操作,但是我们也要考虑实际的意义,比如说让两个Student对象相加好像没有什么意义,但是让两个Money对象相加却存在意义了

    运算符重载使用的operator关键字,只要在指定函数的前面加上operator关键字,就可以实现运算符重载功能了,指定函数是什么呢,每一个运算符对应的函数是不同的,比如说加号运算符对应的是plus()函数 ,减号运算符对应的是miuns()函数,详细请看下图

    语法糖表达式和实际调用函数对照表.png

    下边我们来看一下运算符重载的具体语法结构

    class Obj{
        operator fun plus(obj: Obj):Obj{
            //处理逻辑
        }
    }
    

    上述语法结构中关键字operator和函数名plus都是固定不变的,而接受参数和函数的返回值都是可以自己定义,
    上述表示一个一个对象可以和另一个对象相加 返回一个新的对象
    对应的调用方式如下

    val obj1 = Obj()
    val obj2 = Obj()
    val obj3 = obj1 + obj2
    

    obj1+obj2会在编译的时候转化成obj1.plus(obj2)的调用方式
    下边我们实现一个让两个Money对象相加的功能

    data class Money(val value: Int) {
        operator fun plus(money: Money): Int {
            return money.value + value
        }
    }
    
      val money1 = Money(10)
      val money2 = Money(13) 
      println("money相加得到的结果是:${money1+money2}")
    
    money相加得到的结果是:23
    
    money对象相加.png

    Kotlin允许我们对同一个运算符进行多重重载,这样我们就可以实现Money对象直接进行对数字进行相加

    data class Money(val value: Int) {
        operator fun plus(money: Money): Int {
            return money.value + value
        }
        operator fun plus(i: Int): Int {
            return value + i
        }
    }
    
        val money1 = Money(10)
        val money2 = Money(13)
        println("money相加得到的结果是:${money1 + money2}")
    
        println("money对象直接加数字的结果是:${money1 + 1321}")
    
    money对象直接和数字相加.png

    你还可以对这个Money对象进一步扩展,比如汇率转换、小数点后边金额的四舍五入等,其他的运算符重载使用请参考我们的 语法糖表达式和实际调用函数对照图,如果想使用的话,参考刚才加法运算符的重载去实现就可以了
    请注意,最后一个a in b的语法糖表达式对应的实际调用函数是b.contains(a),a、b对象的
    顺序是反过来的。这在语义上很好理解的
    String类就对contains进行了重载,因此我们判断Hello字符串中是否存在 h 字符串的时候 可以写成下边:

    if ("hello".contains("he")) {
    }
    

    借助运算符重载:

    if ("he" in "hello") {
    }
    

    接下来我们再举个例子增加以下印象
    我们实现一个随机生成字符串长度的函数,代码如下:

    fun getRandomLenghtString(str: String): String {
        val n = (1..20).random()
        val builder = StringBuilder()
        repeat(n) {
            builder.append(str)
        }
        return builder.toString()
    }
    

    repeat(n)是Kotlin的一个标准函数 意思内部的lambda表达式可以重复运行n次
    上述代码的核心思想是将传入的字符串重复N次,如果我们能用 str *N 这种写法的话直接让str字符串重复措辞是不是更爽呢
    如果想要乘以一个数字,那么肯定要在String类中重载乘号运算符才行,但是String类是系统类,我们无法修改,这个时候就可以借助扩展函数向String类中添加函数,可以直接向刚才使用的使用的String.kt文件中添加

    operator fun String.times(n: Int): String {
        val build = StringBuilder()
        repeat(n) {
            build.append(this)
        }
        return build.toString()
    }
    

    解释一下以上代码,首先operator是运算符重载的必须,然后times是乘号运算法所对应的,String.是扩展函数的语法
    现在字符串就有了可以和一个数字相乘的功能了

        println("${"jingkaiqaq"*3}")
    
    扩展函数+运算符重载结果.png

    另外String的Kotlin已经提供了一个用于将字符串重复n边的repeat()函数,因此我们的函数还可以写成如下:

    operator fun String.times(n: Int)=repeat(n)
    

    掌握了上述的功能之后,现在我们可以更改一下getRandomLenghtString代码

    fun getRandomLenghtString(str: String) = str * (1..20).random()
    

    3:infix函数

    val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
    

    map中我们使用 a to b 这种语法结构构件键值对,包括kotlin自带的mapof()函数,之所以我们能实现a to b 这样的语法,是因为Kotlin中提供了一种高级语法结构:infix函数,
    infix函数的作用是可以将编程语言函数调用的语法规则调整一下
    比如a to b这样的写法,实际上等于a to (B)的写法
    下面我们通过两个具体的例子来学习infix函数的用法

    3.1:startswith函数

    startswith函数可以用于判断字符串中是否从某个指定参数开头
    常用方式如下:

    if ("Hello Kotlin".startsWith("Hello")) {
     // 处理具体的逻辑
    }
    

    我们使用一种更具可读性的语法来表达这段代码
    新建一个infix函数编写代码如下:

    infix fun String.beginsWith(prefix: String) = startsWith(prefix)
    

    我们使用一下上边的infix函数创建的beginwith函数:如下所示

    if ("Hello Kotlin" beginsWith "Hello") {
     // 处理具体的逻辑
    }
    

    infix函数允许我们将函数调用时的小数点、括号等计算机相关的语法去掉,从而使用一种更接近英文的语法来编写程序,让代码更加具有可读性

    infix函数由于其语法糖格式的特殊性,有两个比较严格的闲置:
    1:infix函数不可以定义成顶层函数,它必须是某个类的成员函数,可以使用扩展函数的方式将他定义到某个类中,
    2:infix函数只能接受一个参数,类型没有限制

    接下来我们再看一个复杂一点的列子:

    val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
    if (list.contains("Banana")) {
     // 处理具体的逻辑
    }
    

    我们依然可以使用infix函数改造

    infix fun <T> Collection<T>.has(element: T) = contains(element)
    

    可以看到,我们给Collection接口添加了一个扩展函数,这是因为collection是java 及kotlin所有集合的总接口,因此给collection添加一个has函数,那么所有的函数都可以使用了
    现在我们就可以使用如下语法来判断集合中是否存在某个值了:

    val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
    if (list has "Banana") {
     // 处理具体的逻辑
    }
    

    呼,扩展函数和运算符重载、infix函数讲完了,有没有感觉到Kotlin的语法非常有意思,通过这些有意思的语法可以无情的装13了

    下篇文章我们就要来学习Kotlin中最最最最经典的知识——高阶函数了,兄弟坚持住,胜利的曙光就在眼前~~~
    有什么问题欢迎留言指出😜😜😜😜😜😜😜😜😜😜

    相关文章

      网友评论

          本文标题:Kotlin:扩展函数和运算符重载和infix函数

          本文链接:https://www.haomeiwen.com/subject/csgjsltx.html