The Use and Difference of let of with of run of apply of also of Function in Kotlin

  • 2021-08-28 21:07:52
  • OfStack

Compared with Java, Kotlin provides many advanced syntax features. For a beginner of Kotlin, he often writes some code that is not elegant enough. In the source standard library in Kotlin (Standard. kt), a number of built-in functions extended by Kotlin are provided to optimize the coding of kotlin. Standard. kt is part of the Kotlin library, which defines a number of basic functions. Although this source code file has less than 50 lines of code, these functions are very powerful.

1. Simplification of Kotin and lambda of callback function

In Kotlin, the callbacks of some interfaces in Java are optimized, and one lambda function can be used instead. You can simplify writing some unnecessary nested callback methods. However, it should be noted that in lambda expression, 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 expression, and multiple callback methods are not supported.

1. Realize the callback of one interface with Java code.


mView.setEventListener(new ExamPlanHomeEventListener(){

  public void onSuccess(Data data){
   //todo
  }

 });

2. In Kotlin, the callback of one interface is realized without lambda expression (this method is very suitable for kotlin with multiple callback methods in one interface).


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 consistent with using lambda function. We can simplify the above code as follows.


mView.setEventListener({
  data: Data ->
  //todo
})

// Or it can be omitted directly Data, With the aid of kotlin Derivation of intelligence type based on 

mView.setEventListener({
  data ->
  //todo
})

4. If the data parameter in the above code is not used, you can directly remove data


mView.setEventListener({
 //todo

})

5. The above code can also be adjusted. Because the last parameter of setEventListener function is a function, the implementation of parentheses can be directly mentioned outside parentheses


mView.setEventListener(){
  //todo
}

6. Since setEventListener has only one parameter, parentheses can be omitted directly


mView.setEventListener{
 //todo
}

2. let of inline extension function

The let extension function is actually a scope function. When you need to define a variable in a specific scope, the let function is a good choice;

Another function of the let function is to avoid writing some operations to judge null.

1. A general structure for the use of let functions


object.let{
it.todo()// Use in the function body it Substitution object Object to access its public properties and methods 
...
}

// Another 1 Species use   Judge object For null Operation of 
object?.let{// Denote object Not for null Under the conditions, will be implemented let Function body 
it.todo()
}

2. inline extension function + lambda structure at the bottom of let function


@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)

3. Analysis of inline structure of let function

From the source code let function structure, it is only one lambda function block block as a parameter of the function, call let type object T function, then the object is the function parameter. This 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 Transformation 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 applicable to let function

Scenario 1: The most commonly used scenario is to use the let function to process the object system 1 that can be null.

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

6. Comparison of let function before and after use

The code that doesn't use the let function is like this, and it doesn't look elegant enough


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 looks like this


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

0

3. with for inline functions

1. A general structure used by with function


 with(object){
  //todo
 }

2. inline extension function + lambda structure at the bottom of with function


@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

3. Analysis of inline structure of with function

The with function is used slightly differently from the previous functions because it does not exist as an extension. 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 an lambda function block, so the original appearance of the with function is as follows:


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

3

However, since the last argument of the with function is a function, you can put the function outside the parentheses, so the final call form of the with function is as follows:


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

4

4. kotlin and Java Transformation of with Function


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

5

5. Scenarios for the with function

It is suitable for calling multiple methods of the same class. It can omit the duplication of class name and directly call the method of the class. It is often used in onBinderViewHolder in RecyclerView in Android, and the attribute of data model is mapped to UI

6. Comparison of with function before and after use

The implementation in kotlin is not used


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

6

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 = " Difficulty: $gradeInfo |  Number of words: $length |  Post-reading feeling : $numReviews"
    ...  

  }

}

4. run of inline extension function

1. The general structure used by run function


object.run{
//todo
}

2. inline+lambda structure of run function


mView.setEventListener(object: ExamPlanHomeEventListener{

  public void onSuccess(Data data){
   //todo
  }

});

9

3. inline structure analysis of run function

In fact, run function can be said to be a combination of let and with. run function only accepts one lambda function as an argument and returns it in the form of closure, and the return value is the value of the last row or the specified expression of return.

4. kotlin and Java Transformation 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 run function

Applicable to any scenario of let and with functions. Because run function is a combination of let and with, it makes up for the fact that let function must use it parameters to replace objects in the function body. In run function, like with function 1, it can be omitted and directly access the public attributes and methods of instances. On the other hand, it makes up for the problem that with function passes in objects to judge nullness. In run function, it can judge nullness like let function 1

6. Comparison of run function before and after use

Or with the help of the previous example kotlin code


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 = " Difficulty: $gradeInfo |  Number of words: $length |  Post-reading feeling : $numReviews"
    ...  

  }

}

Optimization after using 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 = " Difficulty: $gradeInfo |  Number of words: $length |  Post-reading feeling : $numReviews"
    ...  

  }

}

5. apply of inline extension function

1. A general structure used by apply function


object.apply{
//todo
}

2. inline+lambda structure of 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, apply function and run function are very similar, but the only difference is that they return different values. run function returns the value of the last line of code in the form of closure, while apply function returns the incoming object itself.

4. kotlin and Java Transformation 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 apply function

The whole action function is very similar to the run function, except that the value it returns is the object itself, while the run function returns as a closure and returns the value of the last row. It is based on this difference that its applicable scenario is slightly different from that of run function. When apply1 is used to initialize an object instance, it is necessary to assign values to the attributes in the object. Or it is very common to bind data to View when dynamically inflate produces an View of XML. Particularly in our development there will be some data model to View model conversion instantiation process need to be used.

6. Comparison of apply function before and after use

The code that doesn't use the apply function is like this, and it doesn't look elegant enough


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 looks 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

}

Multi-level 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;
    }

Optimization of apply Function of kotlin


mSectionMetaData?.apply{

//mSectionMetaData Operate when it is not empty mSectionMetaData

}?.questionnaire?.apply{

//questionnaire Operate when it is not empty questionnaire

}?.section?.apply{

//section Operate when it is not empty section

}?.sectionArticle?.apply{

//sectionArticle Operate when it is not empty sectionArticle

}

6. also for inline extension functions

1. The general structure used by also function


object.also{
//todo
}

2. inline+lambda structure of 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

In fact, the structure of also function is very similar to let. The only difference is that the return value is not 1. let returns in the form of closure, returning the value of the last line in the function body. If the last 1 line is empty, it returns a default value of Unit type. The also function returns the incoming object itself

4. class file compiled by 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 also function

Applicable to any scenario of the let function, the also function is very similar to the let function, except that the only difference of 1 is that the last return value of the let function is the return value of the last row and the return value of the also function is to return the current object. 1 can be used for chain calls of multiple extension functions

6. The comparison before and after the use of also function is similar to that of let function

7. Differences between let, with, run, apply and also functions

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

函数名 定义inline的结构 函数体内使用的对象 返回值 是否是扩展函数 适用的场景
let fun T.let(block: (T) -> R): R = block(this) it指代当前对象 闭包形式返回 适用于处理不为null的操作场景
with fun with(receiver: T, block: T.() -> R): R = receiver.block() this指代当前对象或者省略 闭包形式返回 适用于调用同1个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上
run fun T.run(block: T.() -> R): R = block() this指代当前对象或者省略 闭包形式返回 适用于let,with函数任何场景。
apply fun T.apply(block: T.() -> Unit): T { block(); return this } this指代当前对象或者省略 返回this 1、适用于run函数的任何场景,1般用于初始化1个对象实例的时候,操作对象属性,并最终返回这个对象。
2、动态inflate出1个XML的View的时候需要给View绑定数据也会用到.
3、1般可用于多个扩展函数链式调用
4、数据model多层级包裹判空处理的问题
also fun T.also(block: (T) -> Unit): T { block(this); return this } it指代当前对象 返回this 适用于let函数的任何场景,1般可用于多个扩展函数链式调用

Related articles: