This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.
A 🌻 higher-order function instead of a callback
1.1 No Parameter Example
fun main(a) {
pay(Runnable {
println("Callback function..")
})
pay{
println("Higher order functions..")}}fun pay(block: Runnable) {
println("before block")
block.run()
println("end block")}fun pay(block: () -> Unit) {
println("before block")
block()
println("end block")}Copy the code
Output results:
End block Before block The higher-order function end blockCopy the code
It doesn’t make much difference. When the requirements change and I want to add a String to the callback method, how do I do that?
1.2 Examples with Parameters
// Define the interface
interface Consumer {
fun accept(way: String)
}
fun main(a) {
pay(Consumer {
println("The callback function.. it=$it")
})
pay{
println("Higher order functions.. it=$it")}}fun pay(block: Consumer) {
println("before block")
block.accept("Alipay")
println("end block")}// String refers to the method parameter
fun pay(block: (String) - >Unit) {
println("before block")
block("Alipay")
println("end block")}// Int is the return value of the block function
fun pay2(block: (String) - >Int) {
println("before block")
block("Alipay")
println("end block")}Copy the code
- If it is in the form of a callback, you need to create an interface and define parameters. If the parameters become two, you need to create another interface.
- while
Higher order function of KT
It’s more flexible to use.
🌵 inline function
2.1 introduction
- Definition: Prefix the method name with a
inline
It’s an inline function - Purpose: Reduce function calls to optimize performance
- Usage scenario: Adding an inline to the front of each function does not optimize performance if a method’s parameters contain
Higher-order functions
That suggests inline. A typical application scenario is Kotlin’s collection class.
filter
和 map
The arguments in these methods are higher order functions, so these two methods plusinline
After keyword, these two methods are called to reduce nesting and optimize performance, as shown in the following example.
2.2 Non-inline functions
fun main(a) {
pay(Runnable {
println("Callback function..")
})
payNoInline{
println("Higher order functions..")}}fun pay(block: Runnable) {
println("before block")
block.run()
println("end block")}fun payNoInline(block: () -> Unit) {
println("before block")
block()
println("end block")}Copy the code
The relevant Java code decomcompiled by bytecode is as follows:
- Finding that higher-order functions as arguments are no different from method callbacks,
- Additional classes have also been added to the method parameters
Function0
andblock.invoke()
Function call overhead.
2.3 🔥 Inline functions
fun main(a) {
pay(Runnable {
println("Callback function..")
})
payInline{
println("Higher order functions..")}}...fun payInline(block: () -> Unit) {
println("before block")
block()
println("end block")}Copy the code
The relevant Java code decomcompiled by bytecode is as follows:
-
When payInline is called, the method body inside payInline() is taken and executed as a whole with the current higher-order function.
-
The payInline () method is not called and block.invoke() is not called, much more efficient.
-
When a parameter in a function is a higher-order function, it is recommended that you modify the function inline.
Three 🌷 generics
3.1 🔥reified is highly recommended
- Reified is a kt keyword unique to generics. It is used to make something abstract more concrete or real, making generics easier and safer to use.
inline fun <reified T : Activity> Activity.openAct(a) {
startActivity(Intent(this, T::class.java))
}
fun <T : Activity> Activity.openAct(clazz: Class<T>) {
startActivity(Intent(this, clazz))
}
fun main(a){
// Start the Activity
openAct(MyAct::class.java)
// Start the Activity
openAct<MyAct>()
}
Copy the code
When reified is used, it must be inline. Goodbye.class. Java and hello reified
3.2 Upper Bound Constraints (Out or extend)
- Java:
T extends Object
- Kotlin:
T : Object
å’Œout : Object
This means that the type must be a subtype or itself. Out generally returns a generic type as an object, as explained in out covariant below.
The class diagram looks like this:
open class People
open class Man : People(a)class Man1 : Man(a)class Man2 : Man(a)class User<T : Man>
fun <T> createUser(user4: User4<out Man>){}
fun main(a)
var u = User<Man>() // Generics can be themselves
var u1 = User<Man1>() // Generics can be subclasses
// var u2 = User
(
val c1 = createUser(User4(Man1()))
// val c2 = createUser(User4(People())
}
Copy the code
3.3 Lower Bound Constraints (in or super)
- In Java is
? super Object
- Kotlin is
in Object
open class People open class Man : People() class Man1 : Man() class Man2 : Man() class User<T : Man> fun main() {var list: ArrayList<in Man> = ArrayList () list.add(Man()) List. Add ((Man) Man1); List.add (Man1())) // // Because manually add() data must be absolutely secure (the lowest parent: itself) to pass through. So you can't add the parent class directly. Fun getMan(): ArrayList<Man> = ArrayList() fun getMan1(): ArrayList<Man1> = ArrayList() fun getPeople(): ArrayList<People> = ArrayList() list = getMan() // list = getMan()Copy the code
3.4 Type Qualification (WHERE)
interface Fly
class Man
class Man1 : Man.Fly
class Man2 : Man
// Restrict the T passed in to Man or a subclass of it and implement the Fly interface
class User<T>(var t:T) where T: Man, T:Fly
fun main(a) {
var u1 = User(Man1())
// var u2 = User(Man2()
}
Copy the code
3.5 change
3.5.1 track ofOut
If your class returns generics as internal methods, you can use out:
interface Creation<out T> {
fun create(): T
}
Copy the code
Create Creates the specified generic object. So create = output = out.
3.5.2 In (inverter)
If your class takes a generic object as an argument to a function, you can use in:
interface Consumer<in T> {
fun consume(item: T)
}
Copy the code
Consume specifies the generic object. Consume = input = in
3.5.3 Invariant (the same)
If you use generics as both a function parameter and its output, you don’t use either in or out.
interface CreationConsumer<T> {
fun create(a): T
fun consume(item: T)
}
Copy the code
Five for six cycles
// index traversal
for ((index, item) in arrayListOf("a"."b"."c").withIndex()) {
println("$index - $item")// 0-a 1-b 2-c
}
// Bag left bag right
for (i in 1.10.) {
println(i) / / 12345678910
}
// do not do right
for (i in 1 until 10) {
println(i) / / 123456789
}
// descending order - package left package right
for (i in 10 downTo 1) {
println(i) / / 10987654321
}
// Skip - bag left bag right
for (i in 1.10. step 2) {
println(i) / / 13579
}
// do not do right
repeat(10) {
print(it) / / 0123456789
}
Copy the code