博客
关于我
Kotlin语言之:扩展函数和运算符重载讲解
阅读量:273 次
发布时间:2019-03-03

本文共 4470 字,大约阅读时间需要 14 分钟。

1. Kotlin语言之:扩展函数和运算符重载讲解


1.1 扩展函数:

我们先来了解一下什么是扩展函数,扩展函数表示在不修改某个类源码的情况下,仍然可以打开这个类,向该类添加新的函数.为了帮助理解,我们先来思考一个问题:一段字符串中可能包含字母,数字和特殊字符,现在我们希望统计这些特殊字符中字母的数量,你要怎么实现,大多数人想到的是:
/*这里定义一个 单例类 CharacterUtil 方便以后 使用CharacterUtil.lettersCount()直接调用方法 不用创建类的实例*/object CharacterUtil {   //这里定义了一了 lettersCount 方法 用于确定字符串里面有多少字符    fun lettersCount(str: String): Int {           var count = 0        for (char in str) {               if (char.isLetter()) {                   count++            }        }        return count    }}
现在当我们需要统计某个字符串的字母数量时,我们只需要这样:
fun main() {       val str = "wdqwd1293182nidjawdh9%a%WE%2513dgq76d"    var count = lettersCount(str)    println("str 里面有 $count  个字符.")}

运行结果:

在这里插入图片描述

相比于定义一个普通的函数,定义扩展函数只需要在函数名前面加上ClassName.的语法结构,就表示将该函数添加到指定类中. 由于我们想在String类中添加一个扩展函数,接下来我们先创建一个String.kt文件.  文件名没有特殊的要求,但是我建议向哪个类添加扩展函数, 就定义一个同名的Kotlin文件,这样方便以后查找. 当然,扩展函数也是可以定义在任何一个现有类当中,并不一定要创建新的文件. 不过通常来说,最好将它定义为顶层方法,这样就可以让扩展函数拥有全局的访问域

(如果你不知道什么是顶层方法,这里有我以前的讲解

现在向String.kt文件中编写如下代码:

fun String.lettersCount(): Int {       var count = 0    for (char in this) {           if (char.isLetter()) {               count++        }    }    return count}
这里我们将lettersCount()定义成了String类的扩展函数,那么函数中就自动拥有了String实例的上下文.因此lettersCount()函数就不在需要接收一个字符串参数了,而是直接遍历this即可,因为现在this就代表字符串本身.定义好扩展函数后,统计某个字符串中的字母数量只需要这样写:
fun main() {       var count = "wdqwd1293182nidjawdh9%a%WE%2513dgq76d".lettersCount()    println("str 里面有 $count  个字符.")}

运行结果:

在这里插入图片描述

怎么样,是不是很神奇,简直太爽了,我直接起飞.除了String类以外,你可以向任何类中添加扩展函数,Kotlin对此没有限制.如果你可以利用好扩展函数这个功能,你的代码质量和研发效率将会大大提高.

1.2 运算符重载

运算符重载是十分有趣的, 运算符重载是Kotlin提供的一个比较有趣的语法糖,我们知道,在Java里面有许多内置的运算符关键字,如+, -, *, /, %, ++, --等,而Kotlin允许我们将所有的运算符甚至其他的关键字进行重载,从而扩展这些关键字的用法首先我们先来回顾一下运算符的基本语法,相信每个人都用过加减乘除这四种运算符,在编程语言里面,两个数字相加表示求和,两个字符串相加表示拼接字符串.但是Kotlin的运算符重载却允许我们让任意两个对象相加,或者进行其它更不可思议的操作.虽然Kotlin允许这么做,但我们还是要追求实际,比如让两个Student对象相加好像没什么意义,但是两个Money对象相加就变得有意义了,因为钱是可以相加的.运算符重载使用的operator关键字,只要在指定函数的前面加上operator关键字,就可以实现运算符重载的功能了.比如这里我们以加号运算符为例,如果想实现两个对象相加的功能,那么语法结构为:
class Obj {       operator fun plus(obj: Obj):Obj {           //相加的逻辑        return obj    }}
在上述的语法结构里面,关键字operator和函数名plus都是固定不变的,而接收的参数和函数返回值可以根据逻辑自行设定.上述代码表示将两个obj对象相加,最后返回一个新的Obj对象.对应的调用方式如下:
val obj1 = Obj()val obj2 = Obj()val obj3 = obj1 + obj2
这种obj1 + obj2的语法看着好神奇,但其实这里Kotlin给我们提供了一个语法糖,他会在编译的时候转换为obj1.plus(obj2)的调用方式.了解了运算符重载的基本语法后,我们来实现一个有趣的功能:让两个Money对象相加:1.定义Money类的结构,我们先创建一个Money.kt文件,让Money类的主函数接收一个value参数,用于表示钱的金额.
class Money(val value:Int) {   }
2.接下来我们使用运算符重载来实现让两个Money对象相加的功能:
class Money(val value: Int) {       operator fun plus(money: Money): Money {           val sum = value + money.value        return Money(sum)    }}

测试代码:

fun main() {       val money1 = Money(1000)    val money2 = Money(500)    val money3 = money1 + money2    println(money3.value)}

运行结果:

在这里插入图片描述

这样结果是没有问题的,但是Money对象只允许和`Money对象相加`,这样有些不方便,如果Money对象能够直接和数字相加就太好了.接下来我们来做Money对象能和数字相加的功能:
class Money(val value: Int) {       operator fun plus(money: Money): Money {           val sum = value + money.value        return Money(sum)    }//   这里定义了一个plus()方法的重载,使得数字可以直接和Money对象相加    operator fun plus(newValue: Int): Money {           val sum = value + newValue        return Money(sum)    }}

测试代码:

fun main() {       val money1 = Money(1000)    val money2 = Money(500)    val money3 = money1 + money2    println(money3.value)    println("------------------------------")    val money4 = money3 + 500    println(money4.value)}

运行结果:

在这里插入图片描述

这里只介绍加法的重载,如果实现其他运算符的重载,当然也是没有问题的,自己去编写合适的逻辑就可以了,这里提供:《语法糖表达式和实际调用函数对照表》

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

语法糖表达式 实际调用函数
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a++ a.inc()
a– a.dec()
+a a.unaryPlus()
-a a.unaryMinus()
a == b a.equals(b)
a > b a.compareTo(b)
a < b a.compareTo(b)
a >= b a.compareTo(b)
a <= b a.compareTo(b)
a…b a.rangeTo(b)
a[b] a.get(b)
a[b]=c a.set(b,c)
a in b b.contains(a)
!a a.not()
注意 a in b  的语法糖表达式为b.contains(a) ,a, b是反过来的,这其实也很好理解,因为a in b是判断a在没有在b中

实际运用:

Kontin中,我们判断"hello"字符串里面是否有"he",我们可以这样写:
fun main() {       if ("he" in "hello") {           println("yes")    } else {           println("no")    }}
我们也可以这样写:
fun main() {       if ("hello".contains("he")) {           println("yes")    } else {           println("no")    }}

运行结果:

在这里插入图片描述


我们来定义一个随机生成字符串长度字符串的函数:
fun getRandomLengthString(str: String): String {       val n = (1..20).random()    val builder = StringBuilder()    repeat(n) {           builder.append(str)    }    return builder.toString()}
我们可以将代码改写为:
fun getRandomLengthString(str: String): String = str * (1..20).random()


转载地址:http://dikl.baihongyu.com/

你可能感兴趣的文章
从零构建通讯器--5.6 通讯代码精粹之epoll函数实战1(连接池)
查看>>
Ubuntu命令行C++编译链接第三方库及命名空间
查看>>
为什么vs中的地址值是顺序相反的?
查看>>
如何判断两个浮点数是否相等?
查看>>
什么是地址?
查看>>
2019徐州网络赛K XKC's basketball team(结构体排序+二分+RMQ)
查看>>
POJ - 3984 迷宫问题(bfs+路径标记)
查看>>
2017ccpc杭州 E. Master of Subgraph(点分治 + 树dp + bitset)
查看>>
2021牛客寒假算法基础集训营3
查看>>
int 越界处理
查看>>
营收环比增幅近50%,星巴克在经历“劫”后重生吗?
查看>>
苹果进军搜索,背后藏着什么“阳谋”?
查看>>
ARK女神持仓每日跟踪-2021年01月05日
查看>>
js:详解js中的伪数组
查看>>
egg:如何在控制器中拿到前端传的参数
查看>>
vue系列:vue中使用vee-validate3表单验证
查看>>
php:使用php写一个简单的接口
查看>>
mysql:三范式
查看>>
RPA实施指南:企业如何实现流程优化?
查看>>
干货丨RPA售前六技能
查看>>