当前位置:网站首页>Kotlin invoke convention makes kotlin code more concise

Kotlin invoke convention makes kotlin code more concise

2022-06-23 17:46:00 User 9253515

Preface

Recently I saw DSL This thing , I can't help feeling that it can be used Kotlin Some features of can simplify the code , So let's take a look at how it is implemented .

Text

First of all, the principle may not be familiar with Kotlin In general, it feels a little abrupt , So I'm going to start over .

Appointment

Kotlin We must have used the agreement in our daily development , But we didn't pay attention to this noun carefully . The concept of agreement is : Use a different syntax than regular method calls 、 More concise symbols , Calling a function with a special name .

Extract here 2 A key point , One is a more concise symbolic call , One is a specially named function . To put it bluntly, it is to make function calls more concise .

For example, we are most familiar with sets and calls [index] Come on replace get(index), We define a class ourselves , To fulfill this agreement :

data class TestBean(val name: String,val age: Int){
    // The definition is very simple   Use operator Overload operator get Method 
    operator fun  get(index : Int): Any{
        return when(index) {
            0 -> name
            1 -> age
            else -> name
        }
    }

}

Then when we use :

// You can use  []  To replace  get To simplify calling methods 
val testBean = TestBean("zyh",20)
testBean.get(0)
testBean[0]

invoke Appointment

And the above get The agreement is the same ,[] It's called get A more concise way of doing things , Here is a invoke Appointment , Its function is to make objects call methods like functions , Here's an example :

data class TestBean(val name: String,val age: Int){

    // Overload definition invoke Method 
    operator fun invoke() : String{
        return "$name - $age"
    }

}

After defining the above code , Let's use :

val testBean = TestBean("zyh",20)
// Normal call 
testBean.invoke()
// Simplified call after contract 
testBean()

Here we will find testBean Object can call invoke Methods are normal calls , But it can also testBean() Directly to call invoke Method , This is it. invoke The role of the agreement , Let call invoke It's easier .

invoke Conventions and functional types

Now that I understand invoke Appointment , Let's talk to lambda Combine .

We know that a function type is actually an implementation FunctionN The class of the interface , Then when the function type is a function type , Then pass it a lambda,lambda Will be compiled into FunctionN Anonymous inner class of ( Non inline, of course ), And then call lambda It turned into a FunctionN Interface invoke call .

Let's take a look at the example code :

// Define code 
class TestInvoke {
    // Higher order function type variables 
    private var mSingleListener: ((Int) -> Unit)? = null
    // Set a variable 
    public fun setSingleListener(listener:((Int) -> Unit)?){
        this.mSingleListener = listener
    }
    //
    fun testRun() {
        // call invoke function 
        mSingleListener?.invoke(100)
        // Use invoke Appointment , Omit invoke
        if (mSingleListener != null){
            mSingleListener!!(100)
        }
    }

}

After defining the above callback variables , Let's use this callback , Because we know that higher-order functions actually implement FunctionN The class of the interface , That's how it works :

// Be careful , The interface method here is invoke
public interface Function1<in P1, out R> : Function<R> {
    /** Invokes the function with the specified argument. */
    public operator fun invoke(p1: P1): R
}

Then I can directly use the following code to pass parameters :

val function1 = object: Function1<Int,Unit> {
    override fun invoke(p1: Int) {
        Logger.d("$p1")
    }
}
testInvoke.setSingleListener(function1)

It seems reasonable here , Because in testRun In the function, we call invoke function , hold 100 As a parameter , And then this 100 Will be recalled to function1 in , But we deliver lambda When :

val testInvoke  = TestInvoke()
testInvoke.setSingleListener { returnInt ->
    Logger.d("$returnInt")
}

The above code passes lambda It has the same effect as passing an instance of a class , It's just a code block , There are no calls shown invoke What? , So this is a feature , When lambda Used as a parameter when called by a function , It can be regarded as a invoke Automatic call of .

invoke stay DSL Practice in :Gradle rely on

Why do we say this here invoke Rely on? , The big reason is that it is in some DSL There is a good usage in , Let's take a look at Gradle The use of dependency .

The following code is very common :

dependencies {

    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    //...
    }

We are all used to it here , It feels like a configuration item , Not like code , In fact, this is also a piece of code , It's just this style . How to realize this style , Let's make it simple :

class DependencyHandler{
    // Compile Library 
    fun compile(libString: String){
        Logger.d("add $libString")
    }
    // Definition invoke Method 
    operator fun invoke(body: DependencyHandler.() -> Unit){
        body()
    }
}

After the above code is written , We can have the following 3 Call mode :

val dependency = DependencyHandler()
// call invoke
dependency.invoke {
    compile("androidx.core:core-ktx:1.6.0")
}
// Call directly 
dependency.compile("androidx.core:core-ktx:1.6.0")
// Take the recipient lambda The way 
dependency{
    compile("androidx.core:core-ktx:1.6.0")
}

thus it can be seen , The third way of the above code is that we are Gradle A common type of configuration file , This is actually 2 A key point , One is the definition invoke function , One is to define the lambda, Omit when calling this that will do .

summary

In fact, about invoke Agree and lead the recipient lambda The way of writing is becoming more and more popular , Like before anko library , current compose Libraries are written declaratively , After reading the principle , You will find that it is actually very convenient .

Follow up study compose When , Let's add another wave .

Related courses

Android Basic series of tutorials :

Android basic course U- Summary _ Bili, Bili _bilibili

Android basic course UI- Layout _ Bili, Bili _bilibili

Android basic course UI- Control _ Bili, Bili _bilibili

Android basic course UI- Animation _ Bili, Bili _bilibili

Android basic course -activity Use _ Bili, Bili _bilibili

Android basic course -Fragment Usage method _ Bili, Bili _bilibili

Android basic course - Hot repair / The principle of thermal renewal technology _ Bili, Bili _bilibili

In this paper, from https://juejin.cn/post/7047028786969346079, If there is any infringement , Please contact to delete .

原网站

版权声明
本文为[User 9253515]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/01/202201052150194953.html