一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
1.尾递归优化
平常我们可能面临编写递归函数的场景,比如:
fun test5(n: Int): Int =
if (n == 1) {
1
} else
test5(n - 1)
复制代码
每个方法都对应一个栈帧,方法的递归调用会导致方法栈深度过深,存在OOM的风险。Kotlin中提供了尾递归特性
进行优化:
tailrec fun test5(n: Int): Int =
if (n == 1) {
1
} else
test5(n - 1)
复制代码
可以看到尾递归优化就是给方法增加tailrec
,并且递归方法的调用要处于方法的尾部,反编译成java代码看下效果:
可以看到编译器对方法的递归调用进行了优化。
2.中缀方法infix
的实战
中缀方法的修饰是给方法增加infix
声明,并且方法参数只能声明一个,比如:
infix fun String.a(b: String) = "$this - $b"
复制代码
下面我们通过一个案例讲解下:
我们平常肯定有一个这样的需求:传入文件路径String返回File类型
fun makeFile(parent: String, child: String): File {
return File(parent, child)
}
复制代码
这样写起来没什么问题,但是结合中缀函数我们可以实现更优雅的封装,如下:
infix fun String.div(child: String): File = File(this, child)
复制代码
使用如下:
扫描二维码关注公众号,回复:
13788479 查看本文章
fun makeFile(parent: String, child: String): File = parent div child
复制代码
其中parent div child
就等价于File(this, child)
的实现。
这样写起来还不是特别优雅,比如每次都得div
来创建File
对象,div
写起来太麻烦了,而且可读性太差。
为了解决上面的两个问题,我们可以结合运算符重载operator
进行更进一步优化,看下常见的运算符重载函数及对应运算符的映射关系:
表达式 | 转换 |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a % b | a.mod(b) |
a..b | a.rangeTo(b) |
其中有个div
函数重载/
运算符的,借助于这个我们对上面String转File的函数改造下:
infix operator fun String.div(child: String): File = File(this, child)
复制代码
然后就可以这样使用:
fun makeFile(parent: String, child: String): File = parent / child
复制代码
如上所见,直接使用parent / child
就可以完成File的创建,而且/
的可读性更高。