코프링을 제대로 사용하기 위해서는 코틀린의 Scope Functions을 자유롭게 사용할 줄 알아야 한다고 생각하여,
한 번 제대로 정리해 보고자 작성하였습니다.
Scope Functions
먼저, 스코프 함수 let을 어떻게 사용하는지 보겠습니다.
let
data class Person(var name: String, var age: Int, var city: String) {
fun moveTo(newCity: String) { city = newCity }
fun incrementAge() { age++ }
}
fun main() {
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}
}
let을 사용하지 않으면 아래와 같이 작성해야 합니다.
val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)
you'll have to introduce a new variable and repeat its name whenever you use it.
let을 사용하지 않으면, 반환받은 객체의 변수를 사용할 때마다 선언해야 합니다. let을 사용하면 it을 통해 객체 참조를 할 수 있습니다.
let 특징
- NULL이 불가능한 객체에 람다를 실행합니다.
- 로컬 범위에서 변수it)로 표현식을 소개합니다.
Function Object reference Return value Is extension function
Function | Object Reference | Return value | Is extenstion function |
let | it | Lambda result | Yes |
also | it | Context object | Yes |
run | this | Lambda result | Yes |
with | this | Lambda result | No: takes the context object as an argument. |
apply | this | Context object | Yes |
Object reference
the context object is available by a short reference instead of its actual name.
Each scope function uses one of two ways to reference the context object : as a lambda receiver this or as a lambda argument it.
fun main() {
val str = "Hello"
// this
str.run {
println("The string's length: $length")
//println("The string's length: ${this.length}") // does the same
}
// it
str.let {
println("The string's length is ${it.length}")
}
}
// The string's length: 5
// The string's length is 5
- run { … } 은 람다식의 제공자로 str 변수가 this에 해당합니다. $length, ${this.length} 가 str 변수의 문자열 크기를 의미합니다.
- let { … } 은 람다의 인자로 it이 str 변수를 의미합니다.
this
run, with and apply reference the context object as a lambda receiver
In their lambdas, the object is available as it would be in ordinary class functions.
you can omit this when accessing the members of the receiver object, making the code shorter.
having the context object as a receiver (this) is recommended for lambdas that mainly operate on the object's members by calling its functions or assigning values to properties.
- run, with, apply 함수에서 사용된다.
- Receiver Object에 접근하는 경우 this를 생략할 수 있다.
- 외부 객체와 같이 사용하는 경우 혼동이 있을 수 있어, 자신의 함수를 호출하거나 속성에 값을 부여할 때 사용하는 것을 권장합니다.
val adam = Person("Adam").apply {
age = 20 // same as this.age = 20
city = "London"
}
println(adam)
it
let and also reference the context object as a lambda argument.
If the argument name is not specified, the object is accessed by the implicit default name it.
인자명이 구체적이지 않다면, it 을 통해 명시적으로 객체에 접근할 수 있습니다.
when calling the object’s functions or properties, you don’t have the object available implicitly like this.
Hence, accessing the context object via it is better when the object is mostly used as an argument in function calls.
this는 객체의 함수나 변수를 호출할 때 사용할 수 없습니다. 반면, it은 함수 호출에서 사용되어 람다의 인자로 사용됩니다.
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
}
val i = getRandomInt()
println(i)
// INFO: getRandomInt() generated value 13
// 13
- also { … } 의 it는 getRandomInt() 메서드가 호출될 때 생성되는 랜덤 값을 의미합니다.
Return value
- Return : context object
- apply, also
- Return : lambda result
- let, run, with
Context object 반환하는 함수 (apply, also)
The return value of apply and also is the context object itself. they can be included into call chains as side steps
apply와 also 함수는 컨텍스트 객체 자신을 반환합니다. 체인 형태로 포함될 수 있습니다.
val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
.apply {
add(2.71)
add(3.14)
add(1.0)
}
.also { println("Sorting the list") }
.sort()
// Populating the list
// Sorting the list
// (출력 아님) [1.0, 2.71, 3.14]
- also { … } : println 문을 실행하고 numberList(Context object)를 반환합니다.
- apply { … } : add() 메서드를 통해 값을 추가하고, numberList를 반환합니다.
- also { … } : println문 반환
- sort() : numberList 값을 정렬합니다.
Lambda result 반환하는 함수 (let, run, with)
let, run and with return the lambda result. So you can use them when assigning the result to a variable, chaning operatings on the result.
let, run, with 함수는 람다식의 결과를 반환합니다. 그래서, 해당 함수를 결과를 변수에 부여할 때, 결과에 연산을 체이닝 할 때 사용할 수 있습니다.
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {
add("four")
add("five")
count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")
// There are 3 elements that end with e.
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
val firstItem = first()
val lastItem = last()
println("First item: $firstItem, last item: $lastItem")
}
// First item: one, last item: three
Functions
let
- The context object is available as an argument (it).
- The return value is the lambda result.
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }
.filter { it > 3 }
println(resultList)
// [5, 4, 4]
// =====//
// same
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }
.filter { it > 3 }
.let {
println(it)
}
?. 세이프 연산자와의 관계
let is often used to execute a code block containing non-null values.
To perform actions on a non-null objects, use the safe call operator ?. on it and call let with the actions in its lambda
val str: String? = "Hello"
val length = str?.let {
println("let() called on $it")
processNonNullString(it) // OK: 'it' is not null inside '?.let { }'
it.length
}.let(::println)
// let() called on Hello
// 5
- let은 non-null 값에만 사용할 수 있어 nullable 변수에는 세이프 연산자를 이용하여 처리합니다.
with
- The context object is available as a receiver (this).
- The return value is the lambda result.
We recommend using with for calling functions on the context object when you don't need to use the returned result. In code, with can be read as " with this object, do the following. "
with 함수는 반환된 결과를 사용할 필요가 없을 때 context object를 호출할 때 사용하는 것을 추천합니다.
with 함수는 코드에서 “해당 객체로 어떤 행위를 수행합니다”를 알릴 때 사용합니다.
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' is called with argument $this")
println("It contains $size elements")
}
// 'with' is called with argument [one, two, three]
// It contains 3 elements
run
- The context object is available as a receiver (this).
- The return value is the lambda result.
run is useful when your lambda both initializes objects and computes the return value.
run 함수는 람다가 객체를 초기화하고 반환 값을 계산하는 경우에 용이합니다.
class MultiportService(var url: String, var port: Int) {
fun prepareRequest(): String = "Default request"
fun query(request: String): String = "Result for query '$request'"
}
fun main() {
val service = MultiportService("<https://example.kotlinlang.org>", 80)
val result = service.run {
port = 8080
query(prepareRequest() + " to port $port")
}
// the same code written with let() function:
val letResult = service.let {
it.port = 8080
it.query(it.prepareRequest() + " to port ${it.port}")
}
println(result)
println(letResult)
}
// Result for query 'Default request to port 8080'
// Result for query 'Default request to port 8080'
apply
- The context object is available as a receiver (this).
- The return value is the object itself.
we recommend that you use it for code blocks that don’t return a value and that mainly operate on the members of the receiver object.
apply 함수는 값을 반환하지 않고, Receiver object의 속성을 연산할 때 사용합니다.
data class Person(var name: String, var age: Int = 0, var city: String = "")
fun main() {
val adam = Person("Adam").apply {
age = 32
city = "London"
}
println(adam)
}
// Person(name="Adam", age=32, city="London")
also
- The context object is available as an argument (it).
- The return value is the object itself.
also is useful for performing some actions that take the context object as an argument.
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")
// The list elements before adding new one: [one, two, three]
- context object를 인자처럼 사용하여 특정 행위를 수행할 때 사용합니다.
- also 함수는 주로 log, pringln 문을 사용할 때 사용합니다.
참고자료
https://kotlinlang.org/docs/scope-functions.html#context-object-this-or-it
'Kotlin > 코프링' 카테고리의 다른 글
[Kotlin] 코틀린 엘비스 연산자와 firstOrNull 활용법 - 쿼리 시 서버 메모리 최적화 (1) | 2024.12.08 |
---|---|
[Kotlin+Spring] 코프링 Kotlin으로 Spring DTO 클래스 생성하기 - data class (0) | 2024.06.18 |