Use of let, with, run, apply, and also functions in Kotlin series

Tags: Kotlin common tricks


content:

Brief description:

Compared with Java, Kotlin provides many advanced syntax features. For a Kotlin beginner, it is often possible to write some code that is not elegant enough. The source code standard library ( Standard.kt ) in Kotlin provides some built-in functions of Kotlin extensions to optimize kotlin coding. Standard.kt is part of the Kotlin library and it defines some basic functions. Although this source code file is less than 50 lines of code, these functions are very powerful.


First, the simplification of Kotin's lambda of the callback function

In Kotlin, some interface callbacks in Java have been optimized, and a lambda function can be used instead. Can simplify writing some unnecessary nested callback methods. But it should be noted: in lambda expressions, only a single abstract method model is supported, that is to say, there is only one abstract method in the designed interface, which conforms to the rules of lambda expressions, and multiple callback methods are not supported.

  • 1. Implement a callback of an interface with Java code.

     mView.setEventListener(new ExamPlanHomeEventListener(){
    
        public void onSuccess(Data data){
          //todo
        }
    
     });
    
  • 2. Implement the callback of an interface in Kotlin without using lambda expressions (this method is very suitable for kotlin for an interface with multiple callback methods).

    
    mView.setEventListener(object: ExamPlanHomeEventListener{
    
        public void onSuccess(Data data){
          //todo
        }
    
    });
  • 3. If there is only one callback method for the interface in Kotlin , it is suitable to use the lambda function. We can simplify the above code into this.

    mView.setEventListener({
       data: Data ->
       //todo
    })
    
    //或者可以直接省略Data,借助kotlin的智能类型推导
    
    mView.setEventListener({
       data ->
       //todo
    })
  • 4. If the data parameter in the above code is not used , you can directly remove the data

    mView.setEventListener({
      //todo
    
    })
  • 5. The above code can also be adjusted. Since the last parameter of the setEventListener function is a function , the implementation of the parentheses can be directly mentioned outside the parentheses.

    mView.setEventListener(){
       //todo
    }
  • 6. Since the function setEventListener has only one parameter , the parentheses can be omitted directly

    mView.setEventListener{
      //todo
    }

Two, inline extension function let

let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。
  • 1. The general structure of the use of the let function

    object.let{
    it.todo()//在函数体内使用it替代object对象去访问其公有的属性和方法
    ...
    }
    
    //另一种用途 判断object为null的操作
    object?.let{//表示object不为null的条件下,才会去执行let函数体
    it.todo()
    }
  • 2. The inline extension function at the bottom of the let function + lambda structure

    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
  • 3. Analysis of the inline structure of the let function

    Judging from the structure of the source let function, it is a function with only one lambda function block as a parameter. When calling the let function of an object of type T, the object is the parameter of the function. The object can be referred to by it within the function block. The return value is the last line of the function block or the specified return expression.

  • 4. Kotlin and Java conversion of let function

     //kotlin
    
     fun main(args: Array<String>) {
        val result = "testLet".let {
            println(it.length)
            1000
        }
        println(result)
     }
    
     //java
    
     public final class LetFunctionKt {
       public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          String var2 = "testLet";
          int var4 = var2.length();
          System.out.println(var4);
          int result = 1000;
          System.out.println(result);
       }
    }
    
    
  • 5. Scenarios where the let function is applicable

    Scenario 1: The most common scenario is to use the let function to process a nullable object.

    Scenario 2: Then it is necessary to make it clear that a variable can be used within a specific scope.

  • 6. Comparison before and after the use of the let function

    The code without the let function is like this, it doesn't look elegant

    mVideoPlayer?.setVideoView(activity.course_video_view)
        mVideoPlayer?.setControllerView(activity.course_video_controller_view)
        mVideoPlayer?.setCurtainView(activity.course_video_curtain_view)

    The code after using the let function is like this

    mVideoPlayer?.let {
           it.setVideoView(activity.course_video_view)
           it.setControllerView(activity.course_video_controller_view)
           it.setCurtainView(activity.course_video_curtain_view)
    }
    

3. With inline function

  • 1. The general structure used by the with function

     with(object){
       //todo
     }
  • 2. The inline extension function at the bottom of the with function + lambda structure

    @kotlin.internal.InlineOnly
    public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
    
  • 3. Analysis of the inline structure of the with function

    The with function is slightly different from the previous functions because it does not exist in an extended form. It takes an object as a parameter of a function, which can be referred to by this in a function block. The return value is the last line of the function block or the specified return expression.

    It can be seen that the with function receives two parameters, an object receiver of type T and a lambda function block, so the original appearance of the with function is as follows:

    
    val result = with(user, {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        })

    But since the last parameter of the with function is a function, the function can be mentioned outside the parentheses, so the final call form of the with function is as follows:

    val result = with(user) {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        }
  • 4. Kotlin and Java conversion of with function

    //kotlin
    
    fun main(args: Array<String>) {
        val user = User("Kotlin", 1, "1111111")
    
        val result = with(user) {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        }
        println("result: $result")
    }
    
    //java
    
     public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          User user = new User("Kotlin", 1, "1111111");
          String var4 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
          System.out.println(var4);
          int result = 1000;
          String var3 = "result: " + result;
          System.out.println(var3);
       }
    
  • 5. Applicable scenarios of the with function

    It is suitable for calling multiple methods of the same class. You can save the repetition of the class name and call the method of the class directly. It is often used in the onBinderViewHolder of the RecyclerView in Android, and the attributes of the data model are mapped to the UI.

  • 6. Comparison before and after the use of the with function

    Not using the implementation in kotlin

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
    
       ArticleSnippet item = getItem(position);
            if (item == null) {
                return;
            }
            holder.tvNewsTitle.setText(StringUtils.trimToEmpty(item.titleEn));
            holder.tvNewsSummary.setText(StringUtils.trimToEmpty(item.summary));
            String gradeInfo = "难度:" + item.gradeInfo;
            String wordCount = "单词数:" + item.length;
            String reviewNum = "读后感:" + item.numReviews;
            String extraInfo = gradeInfo + " | " + wordCount + " | " + reviewNum;
            holder.tvExtraInfo.setText(extraInfo);
            ...
    }
    

    Implementation of kotlin

    override fun onBindViewHolder(holder: ViewHolder, position: Int){
       val item = getItem(position)?: return
    
       with(item){
    
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
           holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
           holder.tvExtraInf.text = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
    
       }
    
    }
    

Fourth, the run of the inline extension function

  • 1. The general structure used by the run function

    object.run{
    //todo
    }
  • 2. The inline+lambda structure of the run function

    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.run(block: T.() -> R): R = block()
  • 3. Inline structure analysis of run function

    The run function can actually be said to be a combination of two functions, let and with. The run function only receives a lambda function as a parameter and returns it in the form of a closure. The return value is the value of the last line or the specified return expression.

  • 4. Kotlin and Java conversion of run function

    //kotlin
    
    fun main(args: Array<String>) {
        val user = User("Kotlin", 1, "1111111")
    
        val result = user.run {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        }
        println("result: $result")
    }
    
    //java
    
      public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          User user = new User("Kotlin", 1, "1111111");
          String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
          System.out.println(var5);
          int result = 1000;
          String var3 = "result: " + result;
          System.out.println(var3);
       }
    
  • 5. Applicable scenarios of the run function

    Applicable to any scenario of let and with functions. Because the run function is a combination of two functions, let and with, to be precise, it makes up for the let function must use the it parameter to replace the object in the function body. In the run function, it can be omitted like the with function and directly access the public properties and method, on the other hand, it makes up for the problem of judging the object passed into the with function. In the run function, it can be handled like the let function.

  • 6. Comparison before and after the use of the run function

    Or use the kotlin code of the previous example

    override fun onBindViewHolder(holder: ViewHolder, position: Int){
       val item = getItem(position)?: return
    
       with(item){
    
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
           holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
           holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
    
       }
    
    }

    Optimization after using the run function

    override fun onBindViewHolder(holder: ViewHolder, position: Int){
    
      getItem(position)?.run{
          holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
           holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
           holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
           ...   
    
       }
    
    }
    

Five, inline extension function apply

  • 1. The general structure used by the apply function

    object.apply{
    //todo
    }
  • 2. The inline+lambda structure of the apply function

    @kotlin.internal.InlineOnly
    public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
  • 3. Inline structure analysis of apply function

    Structurally, the apply function is very similar to the run function. The only difference is that they return different values. The run function returns the value of the last line of code in the form of a closure, while the apply function returns the incoming object itself. .

  • 4. Kotlin and Java conversion of apply function

    //kotlin
    
    fun main(args: Array<String>) {
        val user = User("Kotlin", 1, "1111111")
    
        val result = user.apply {
            println("my name is $name, I am $age years old, my phone number is $phoneNum")
            1000
        }
        println("result: $result")
    }
    
    //java
    
    public final class ApplyFunctionKt {
       public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          User user = new User("Kotlin", 1, "1111111");
          String var5 = "my name is " + user.getName() + ", I am " + user.getAge() + " years old, my phone number is " + user.getPhoneNum();
          System.out.println(var5);
          String var3 = "result: " + user;
          System.out.println(var3);
       }
    }
    
  • 5. Applicable scenarios of the apply function

    The overall function is very similar to the run function, the only difference is that the value it returns is the object itself, while the run function returns in the form of a closure, returning the value of the last row. It is based on this difference that its applicable scenarios are slightly different from the run function. apply is generally used when an object instance is initialized, and it is necessary to assign values ​​to the properties in the object. Or when dynamically inflate an XML View, you need to bind data to the View, which is very common. Especially in our development, there will be some data models that need to be used in the process of converting and instantiating the View model.

  • 6. Comparison before and after the use of the apply function

    The code without the apply function is like this, which doesn't look elegant

    mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null)
            mSheetDialogView.course_comment_tv_label.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_score.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_cancel.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_tv_confirm.paint.isFakeBoldText = true
            mSheetDialogView.course_comment_seek_bar.max = 10
            mSheetDialogView.course_comment_seek_bar.progress = 0

    The code after using the apply function is like this

    mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null).apply{
       course_comment_tv_label.paint.isFakeBoldText = true
       course_comment_tv_score.paint.isFakeBoldText = true
       course_comment_tv_cancel.paint.isFakeBoldText = true
       course_comment_tv_confirm.paint.isFakeBoldText = true
       course_comment_seek_bar.max = 10
       course_comment_seek_bar.progress = 0
    
    }
    

    Multilevel Empty Judgment Problem

        if (mSectionMetaData == null || mSectionMetaData.questionnaire == null || mSectionMetaData.section == null) {
                return;
            }
            if (mSectionMetaData.questionnaire.userProject != null) {
                renderAnalysis();
                return;
            }
            if (mSectionMetaData.section != null && !mSectionMetaData.section.sectionArticles.isEmpty()) {
                fetchQuestionData();
                return;
            }

    Kotlin's apply function optimization

    mSectionMetaData?.apply{
    
    //mSectionMetaData不为空的时候操作mSectionMetaData
    
    }?.questionnaire?.apply{
    
    //questionnaire不为空的时候操作questionnaire
    
    }?.section?.apply{
    
    //section不为空的时候操作section
    
    }?.sectionArticle?.apply{
    
    //sectionArticle不为空的时候操作sectionArticle
    
    }
    

6. Also of inline extension function

  • 1. The general structure used by the also function

    object.also{
    //todo
    }
  • 2. The inline+lambda structure of the also function

    @kotlin.internal.InlineOnly
    @SinceKotlin("1.1")
    public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
  • 3. Inline structure analysis of also function

    The structure of the also function is actually very similar to let. The only difference is that the return value is different. Let returns in the form of a closure, returning the value of the last line in the function body. If the last line is empty, it returns a default value of type Unit. . The also function returns the passed object itself

  • 4. The compiled class file of the also function

    //kotlin
    
    fun main(args: Array<String>) {
        val result = "testLet".also {
            println(it.length)
            1000
        }
        println(result)
    }
    
    //java
    
    public final class AlsoFunctionKt {
       public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          String var2 = "testLet";
          int var4 = var2.length();
          System.out.println(var4);
          System.out.println(var2);
       }
    }
  • 5. Applicable scenarios of the also function

    Applicable to any scenario of the let function, the also function is very similar to let, but the only difference is that the final return value of the let function is the return value of the last line and the return value of the also function is the current object. Generally, it can be used for chaining calls of multiple extension functions

  • 6. Comparison before and after the use of the also function

    Similar to let function

Seven, let, with, run, apply, also function difference

Through the introduction of the above functions, it is very convenient to optimize the code writing in kotlin. Overall, the functions of several functions are very similar, but they are different. The scenarios used have the same places. For example, the run function is a combination of let and with. The following table can clearly compare their differences.

Function name Define the structure of the inline Objects used in the body of the function return value Is it an extension function Applicable scenarios
let fun T.let(block: (T) -> R): R = block(this) it refers to the current object Return in closure form Yes It is suitable for handling operation scenarios that are not null
with fun with(receiver: T, block: T.() -> R): R = receiver.block() this refers to the current object or omitted Return in closure form no It is suitable for calling multiple methods of the same class. You can save the repetition of the class name and call the method of the class directly. It is often used in the onBinderViewHolder of the RecyclerView in Android, and the attributes of the data model are mapped to the UI.
run fun T.run(block: T.() -> R): R = block() this refers to the current object or omitted Return in closure form Yes Applicable to any scenario of let and with functions.
apply fun T.apply(block: T.() -> Unit): T { block(); return this } this refers to the current object or omitted return this Yes 1. Applicable to any scenario of the run function. It is generally used to manipulate object properties when initializing an object instance, and finally return the object.
2. When dynamically inflate an XML View, you need to bind data to the View.
3. Generally, it can be used for chained calls of multiple extension functions .
4. The problem of multi-level package processing of data model
also fun T.also(block: (T) -> Unit): T { block(this); return this } it refers to the current object return this Yes Applicable to any scenario of let function, generally can be used for chained calls of multiple extension functions

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325382754&siteId=291194637