你需要懂的Kotlin开发技巧之六

一起养成写作习惯!这是我参与「掘金日新计划 · 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代码看下效果:

image.png

可以看到编译器对方法的递归调用进行了优化。

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的创建,而且/的可读性更高。

猜你喜欢

转载自juejin.im/post/7086234211333439519