preface

Those of you familiar with Kotlin know that there are some very useful functions in Kotlin. Such as run, with, let, also, apply. We use these functions when we write code, but do we pay attention to how they are implemented? Or do we know the difference between these functions? If not, this article will take you through some of the basic functions in Kotlin. Before we look at these functions, let’s first look at a concept called scoped functions

Scope function

There is a class of functions in Kotlin whose sole purpose is to execute a block of code in the context of an object. When such a function is called on an object and a lambda expression is provided, it forms a temporary scope. In this scope, the object can be accessed without its name. These functions are called scoped functions. There are five types: let, run, with, apply and also.

There are three main differences between these scope functions:

  • Is it an extended function or is it a normal function
  • The context object is this or it
  • The return value is itself or the last line of the lambda

Having said what scoped functions are, let’s start parsing them from source code.

The run function

/** * the first is the run function */
fun learnRun(a){
    val name = "write code"
    val name2 = run {
        val name = "read code"
        println(name) // Print read code
        name
    }
    println(name) // Print write code
    println(name==name2) / / output true
}

// Run function source code
// Arguments to the run function: takes an argument of type R. The type of the function -> is a no-parameter function and returns a function of type R
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
Copy the code

In this example, there is a delimited scope inside the learnRun function, which contains a complete implementation of the operation where the name variable is redefined and initialized to Read Code before output.

The scope function itself may not seem very useful. But it’s important to note that its return value is the last object inside the scope.

The run function is a non-extended function that has no acceptors and returns the result of a lambda expression.

With the function

A common function is actually a shorthand encapsulation, which is suitable for calling multiple methods or attributes of the same class. In this case, the class name can be omitted and the method of the class can be directly called. Typical application scenarios are as follows:

fun learnWith(a){
    val person = Person("hui"."boy")
    with(person){
        print(name)
        print(sex)
    }
}
Copy the code
// With function source code
 // Pay special attention! The block argument is a function type with a receiver. This in T.()->R represents an instance of itself, so it can be saved
public inline fun <T, R> with(receiver: T, block: T. () - >R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}
 
Copy the code

Note: Kotlin provides the ability to call an instance of a function type with a receiver (providing a receiver object), as shown in T.() -> R. Inside such a function literal, the recipient object passed to the call becomes implicit this so that members of the recipient object can be accessed without any additional qualifiers, and the recipient object can also be accessed using this expression.

Features of the with function: a non-extension function, the context object acts as the receiver of a lambda expression, but inside a lambda expression, it can be used as the receiver (this). The return value is the result of a lambda expression.

T.l et function

For the t.et function declaration, you’ll notice that t.et passes itself into the function block: (T). Take a context object as a lambda expression parameter. If no parameter name is specified, the object can be accessed with the implicit default name it. It is shorter than this, and expressions with it are usually easier to read. However, when calling object functions or properties, you cannot access objects implicitly like this. You must use the IT. Call to access the corresponding property.

fun learnLet(a){
    var person:Person? = Person("hui"."boy") person? .let { print(it.name) print(it.sex) } }Copy the code
 ​
 / / T.l et the source code
 //let is an inline extension function that extends any type, as represented here by the paradigm
 // Takes a function type argument that is this object, and returns a function of type R
 @kotlin.internal.InlineOnly
 public inline fun <T, R> T.let(block: (T) - >R): R {
     / / contract
     contract {
         callsInPlace(block, InvocationKind.EXACTLY_ONCE)
     }
     // We can see that the function with the function argument is called, the pass argument is the object instance that called the let function, and the return value is the return value of the function argument call
     return block(this)}Copy the code

T function: an extension function that takes a context object as a lambda expression parameter. When lambda parameters are not declared, it can be used to refer to the context object. The return value is the result of a lambda expression.

T.r UN function

fun learnTRun(a){
    var person:Person? = Person("hui"."boy") person? .run { print(name) print(sex) } }Copy the code
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T. () - >R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
Copy the code

The t. run function is very similar to the t. et function, except that they take different arguments, one of which is of type IT and the other is of type this

Features of the t. run function: an extension function that takes the context object as the acceptor of a lambda expression. Inside a lambda expression, it can be used as the acceptor (this). The return value is the result of a lambda expression.

T.a lso function

The t. lash extension function is similar to the t. lash extension function, except that it returns the value of the last row in the body of the function as a closure, while the also extension function returns the object itself.

 public inline fun <T> T.also(block: (T) - >Unit): T {
     contract {
         callsInPlace(block, InvocationKind.EXACTLY_ONCE)
     }
     block(this)
     // Returns the calling object itself
     return this
 }
Copy the code

An extension function that takes a context object as a lambda expression parameter. When lambda parameters are not declared, it can be used to refer to the context object. Return a value context object.

T.a pply function

The t. ply extension function is similar to the t. run, except that it returns the value of the last line in the body of the function as a closure, whereas the t. ply extension returns the object itself.

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T. () - >Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
Copy the code

Features of the t.apply function: an extension function that treats the context object as the receiver of a lambda expression, but inside a lambda expression, it can be used as the receiver (this). Return a value context object.

How to choose which parameter this or it

Select this scenario: you can omit this when accessing the receiver object to make your code shorter. By contrast, if this is omitted, it becomes difficult to distinguish between members of the recipient object and external objects or functions. Therefore, for lambda expressions that operate primarily on object members (calling their functions or assigning their attributes), it is recommended that the context object be the receiver (this)

Scenarios for choosing IT: It is better to use it as a context object when the context object is primarily used as a parameter in a function call in scope. It is also better if you use multiple variables in a code block.

conclusion

function type Parameter type (it,this) Return value (itself, last line)
run Nonexpanding function it The last line
with Nonexpanding function this The last line
T.let Expanding function it The last line
T.run Expanding function this The last line
T.also Expanding function it itself
T,apply Expanding function this itself

Note: this is my first blog, what is wrong, please correct.