With Kotorin ―― 7. Scoping Function

Overview / Description

In "Spring with Kotorin-- 6. Asynchronous processing", the following description was made when setting the property of the instance. It was.

    @Bean
    fun normalTaskExecutor(): TaskExecutor  = ThreadPoolTaskExecutor().apply {
        corePoolSize = 1
        setQueueCapacity(5)
        maxPoolSize = 1
        setThreadNamePrefix("NormalThread-")
        setWaitForTasksToCompleteOnShutdown(true)
    }

It creates a ThreadPoolTaskExecutor instance and then lambda operates on that instance.

In this way, the function used to operate in lambda following the instance is called ** scope function **. Using this format is convenient in the following points.

--Operations to instances can be grouped in a lambda --Eliminate code redundancy --The range of influence of the operation can be contained only in the lambda

Kotlin has multiple scope functions. Each one is used differently, so let's check what it looks like.

Assumptions / Environment

It is implemented in the following environment, but it is not a prerequisite.

Runtime version

Spring Dependencies

Development environment

Procedure / Explanation

The scope functions are as follows.

Let's look at each function.

Definition of scope function

First, let's look at the definition of each scope function.

Scoping Function Definition Example
with fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() val r: R = with(T()) { this.foo(); this.toR() }
run fun <T, R> T.run(block: T.() -> R): R = block() val r: R = T().run { this.foo(); this.toR() }
let fun <T, R> T.let(block: (T) -> R): R = block(this) val r: R = T().let { it.foo(); it.toR() }
apply fun T.apply(block: T.() -> Unit): T { block(); return this } val t: T = T().apply { this.foo() }
also fun T.also(block: (T) -> Unit): T { block(this); return this } val t: T = T().also { it.foo() }

Looking at the definition, you can see that the definition method is largely different from the following two viewpoints.

--Representation of receiver --T. ()-> R: Receiver type T extension function --(T)-> R: Handle receiver type T as an argument

Summarizing the above, we have the following matrix.

scopingfunction.png

Code sample

Prepare the following data class as a receiver object.

data class Person(
        var name: String,
        var age: Int
) {
    private lateinit var hobby: String
    fun nameToUpperCase() {
        name = name.toUpperCase()
    }

    fun increaseAge() {
        age++
    }

    fun defineHobby(hobby: String) {
        this.hobby = hobby
    }

    fun displayHobby() = this.hobby

    fun toStringAddon(): String {
        return "Person(name=$name, age=$age, hobby=$hobby)"
    }
}

with with is an ordinary function, not an extension function of the receiver. Therefore, it is called differently from other scope functions.

    val foo: Person = Person("with", 20)

    with(foo){
        foo.increaseAge()
        println(foo)
    }

run run uses this to represent the receiver in the lambda. Therefore, it is ** optional **. In the following, it is explicitly described, but it is often omitted because it is redundant. It also returns the lambda result (last line).

    val foo: Person = Person("run", 20)

    return foo.run {
        nameToUpperCase()
        println(this)
        this.name
    }

let let behaves much like run, but The receiver representation in the lambda is ʻit`. Therefore, it can be ** alias **. Replace it with a keyword that makes sense It is used to improve readability.

    val foo: Person = Person("let", 20)

    return foo.let { it ->
        println(it)
        it.defineHobby("Kotlin")
        println(it.toStringAddon())
        it.displayHobby()
    }

apply ʻApplyreturns the receiver itself. Therefore, it is used when operating the receiver itself. It is used for many purposes such as setting and changing properties. The receiver is represented bythis`. Here, it is omitted in the function call of the receiver.

    val foo: Person = Person("apply", 20)

    foo.apply {
        println(this)
        nameToUpperCase()
        increaseAge()
        println(this)
    }

also You can think of ʻalso as the receiver representation of apply is now ʻit. Therefore, it is used when it is necessary to give an alias to the receiver to improve readability.

    val foo: Person = Person("also", 20)

    return foo.also { it ->
        println(it)
        it.nameToUpperCase()
        it.increaseAge()
        it.defineHobby("Kotlin")
        println(it.toStringAddon())
    }

Summary / Looking back

Personally, the proper use of scope functions is determined only by whether or not you want to return a receiver as a return value. After that, if the this keyword seems to be complicated, I will use it properly by refraining from it.

scopefunction-selection.png

This source

Recommended Posts

With Kotorin ―― 7. Scoping Function
Spring with Kotorin ―― 1. SPRING INITIALIZR
Serverless Function with Micronaut
Spring with Kotorin --3. Omitting curly braces from the function
Introduced graph function with rails
Java to play with Function
Spring with Kotorin --8 Repository layer
Spring with Kotorin --6 Asynchronous processing
Spring with Kotorin ―― 7. Service layer
Login function with Spring Security
Login function implementation with rails
Implement search function with form_with
Spring with Kotorin --4 REST API design
Implemented authentication function with Spring Security ②
Real-time comment function with Action Cable (2/2)
Implemented mail sending function with rails
Fibonacci sequence with (memoization) recursive function
Create pagination function with Rails Kaminari
Implemented authentication function with Spring Security ①
Real-time comment function with Action Cable (1/2)
[Rails withdrawal] Create a simple withdrawal function with rails
Try to implement login function with Spring-Boot
Authentication function with Play Framework [Registration and authentication]
Make a login function with Rails anyway
Add pdf file posting function with carrierwave
How to implement TextInputLayout with validation function
Implement paging function with Spring Boot + Thymeleaf
Create an or search function with Ransack.