Make writing a habit together! This is the 13th day of my participation in the “Gold Digging Day New Plan · April More Text Challenge”. Click here for more details.
1. Tail recursive optimization
Normally we might be faced with writing recursive functions, such as:
fun test5(n: Int): Int =
if (n == 1) {
1
} else
test5(n - 1)
Copy the code
Each method corresponds to a stack frame. Recursive calls to the method will cause the stack to be too deep, and there is a risk of OOM. Kotlin provides tail-recursive features for optimization:
tailrec fun test5(n: Int): Int =
if (n == 1) {
1
} else
test5(n - 1)
Copy the code
As you can see, tail-recursive optimization is to add tailrec to a method, and the call to the recursive method should be at the end of the method. Decompile into Java code to see the effect:
You can see that the compiler optimizes recursive calls to methods.
2. Infix methodinfix
The actual combat
Infix methods add infix declarations to methods, and only one method argument can be declared, such as:
infix fun String.a(b: String) = "$this - $b"
Copy the code
Let’s explain it through a case:
We usually have one such requirement: pass in the File path String to return type File
fun makeFile(parent: String, child: String): File {
return File(parent, child)
}
Copy the code
This is fine to write, but with infix functions we can achieve more elegant encapsulation, as follows:
infix fun String.div(child: String): File = File(this, child)
Copy the code
Use as follows:
fun makeFile(parent: String, child: String): File = parent div child
Copy the code
Parent div Child is equivalent to the implementation of File(this, child).
It’s not particularly elegant to write this way. For example, every time you have to create a File object with a div, div is too cumbersome to write and not very readable.
To solve the above two problems, we can combine the overloaded operator operator to further optimize. Let’s take a look at the common overloaded operator functions and the mapping between the corresponding operators:
expression | conversion |
---|---|
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) |
The div function overloads the/operator, so we can change the function from String to File:
infix operator fun String.div(child: String): File = File(this, child)
Copy the code
It can then be used like this:
fun makeFile(parent: String, child: String): File = parent / child
Copy the code
As you can see, using parent/child directly creates files, and/is much more readable.