当前位置: 首页 > news >正文

【编程语言】Kotlin快速入门 - 高阶函数与运算符重载

运算符重载

Java中的运算符基本只能应用于基本类型的+-*/,并不能对类对象进行这一系列的运算符操作,而Kotlin则赋予了我们使类对象也具有这种运算符操作,并且具体操作我们可以自定义。

假设我们存在一个类:Balance代表用户的余额,我们需要在其内部新增一个方法,并使用operator关键词进行修饰

注意,函数名是有要求的,具体的操作符需要的函数名是不一致的,具体操作符与函数名的映射请参加下文。

class Balance(val value: Int) {operator fun plus(m : Balance) = Balance(this.value + m.value)
}

在这段代码中我们新增了plus函数,它会在Balance对象调用+操作时,实际调用的是Balance内部这个plus方法,实例如下:

fun main() {val a = Balance(5)val b = Balance(1)val c = a + bprintln(c.value)
}

输出结果:6

运算符表达式和实际调用函数对照表
运算符实际调用函数
a+ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
a++a.inc()
a–a.dec()
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()
a == ba.equals(b)
a > ba.equals(b)
a < ba.equals(b)
a >= ba.equals(b)
a <= ba.compareTo(b)
a…ba.rangeTo(b)
a[b]a.get(b)
a[b] = ca.set(b, c)
a in bb.contains(a)
拓展函数与运算符重载的实践

当我们学习完拓展函数与运算符重载后,我们来举个实践例子,在开发的过程中我们有可能会让字符串的内容重复几遍,比如我想让abc这三个字符在一个字符串中重复n此,你可能会想到写个工具类再写一个for循环,但是学习完拓展函数与运算符重载之后,我们就可以理由Kotlin提供给我们的这两个语法糖来试试:

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

其中我们使用operator来告诉Kotlin此函数为运算符重载,然后使用String.times将这个函数做为String的拓展函数,在方法体内我们又使用repeat来使res重复添加n次。

然后我们就可以使用:“abc” * 3,的操作来使字符串重复三遍

fun main() {println("abc" * 3)
}
// 输出结果:abcabcabc

高阶函数

从本节开始,我们将告别基础知识,转向Kotlin高级用法。

高阶函数的定义

高阶函数与Lambda是密不可分的,在Lambda中我们当时使用maxBy函数去求最长的字符串时讲到,maxBy是需要传入一个Lambda参数的,如果你想实现类似这种的,就需要用到高阶函数,那么高阶函数是什么呢?如果一个函数接收另一个函数作为参数,或者返回值的类型是 另一个函数,那么该函数就称为高阶函数。

在Java中我们不能将一个函数做为另外一个函数的参数,而Kotlin却增加了函数类型的概念,如果我们将这种函数类型添加到一个函数的参数声明或者返回值声明当 中,那么这就是一个高阶函数了。

高阶函数语法规则:

(String, Int) -> Unit

函数括号内是该函数需要接收什么参数,以及它的返回值是什么,这里的Unit相当于Java中的void关键字,将上述声明添加到方法中,那么此方法就称为高阶函数。

fun times(func : (String, Int) -> Unit) {func("hello", 123)
}

高阶函数允许让函数类型的参数来决定函数的执行逻辑。即使是同一个高阶函数,只要传入不同的函数类型参数,那么它的执行逻辑和最终的返回结果就可能是完全不同的

高阶函数实践

知道了高阶函数能够做什么之后,我们来尝试自定义一个我们自己的高阶函数。

定义函数num1AndNum2,参数1为数字1,参数2为数字2,参数3为对应的高阶函数操作,我们在这个方法内返回了这个函数参数的调用,这意味着这个函数的结果是由我们传递的函数参数所决定的。

fun num1AndNum2(n1 : Int, n2 : Int, oper : (Int, Int) -> Int) : Int {return oper(n1, n2)
}

然后在HigherOrderFunction.kt文件中添加以下内容,其中plus主要返回n1和n2的相加结果,minus返回n1-n2的结果:

fun plus(n1 : Int, n2 : Int): Int {return n1 + n2
}fun minus(n1 : Int, n2 : Int): Int {return n1 - n2
}

接着,我们将参数和具体的函数参数传递给num1AndNum2这个函数

fun main() {println(num1AndNum2(1, 2, ::plus))
}

输出结果:3

但是你会想,这样也太麻烦了吧,我为什么不直接去调用HigherOrderFunction.kt,但是函数参数不仅可以使用函数引用的方式(上文提到的方式),还可以使用Lambda、匿名函数、成员引用等,比如我们可以不用在HigherOrderFunction.kt中定义函数,而是在调用num1AndNum2时,使用Lambda效果也是一样的:

println(num1AndNum2(1, 2) { n1, n2 -> n1 + n2 })
高阶函数与apply

使用高阶函数还可以实现apply提供一个对象上下文的功能,新增如下方法:

fun StringBuffer.build(block: StringBuffer.() -> Unit): StringBuffer {block()return this
}

可以看到我们这里使用到了拓展函数,但是奇怪的点是函数参数并不是我们之前提到的高阶函数定义的标准格式,实际情况是,我们现在使用的才是高阶函数的标准形式,在函数参数括号前使用ClassName.来告诉Kotlin,我的这个高阶函数是定义在哪个Class里面的。

fun main() {val list = listOf("a", "b", "c")val res = StringBuffer().build {append("开始完成任务... \n")for (s in list) {append("正在完成: $s \n")}}println(res)
}

然后我们就可以不用在使用apply来提供一个对象的上下文了。


http://www.mrgr.cn/news/57162.html

相关文章:

  • 运动监测网站毕设基于SpringBootSSM框架的计算机毕业设计
  • redis 第155节答疑 源码分析Hash类型ziplist结构和zlentry实体解析
  • STM32+CubeMX -- 开发辅助工具
  • scala 抽象类
  • 使用Gitblit搭建Git服务器
  • Kubernetes部署练习
  • 均匀随机掉落算法
  • 梦开始的地方 -- 两数求和
  • c++查看运行时类型
  • Thread类
  • react优化
  • Napkins:开源 AI 开发工具,实现截图或线框图到网页应用的快速转换
  • konva不透明度,查找,显示,隐藏
  • vTESTstudio系列14--vTESTstudio中自定义函数介绍1
  • RHCE时间服务器
  • Vscode + EIDE +CortexDebug 调试Stm32(记录)
  • Kamailio 网络拓扑案例分享
  • C++ set和map的模拟实现
  • Llama Tutor:开源 AI 个性化学习平台,根据主题自动制定学习计划
  • RTDETR 引入 MogaBlock | 多阶门控聚合网络 | ICLR 2024
  • ThinkPad中键打开网页关闭网页失灵
  • 【Linux】线程互斥与同步,生产消费模型(超详解)
  • Redis-05 Redis发布订阅
  • 得物App3D博物馆亮相“两博会”,正品保障助力消费体验升级
  • 10.23Python_matplotlib_乱码问题
  • 三菱FX5U PLC程序容量设置