Scope Function 이라는 함수명에서 알 수 있듯이,
이 함수들을 람다식을 이용해서 호출하면 일시적인 Scope(범위)가 생기게 되고,
이 범위 안에서는 전달된 객체에 대해 "it" 또는 "this" 라는 Context Object를 통해서 접근하게 됩니다.
두 가지 차이점
Scope Function에는 서로 다른 두 가지 주요 차이점이 있습니다.
- Context Object를 참조하는 방법 (this, it)
- Return value
Context Object: this or it
Scope Function 람다식 내에서 Context Object는 실제 객체명 대신, "it" 또는 "this" 키워드로 접근하게 됩니다.
class Person (var name: String, var age: Int)
fun main() {
val person = Person("홍길동", 30)
//this로 참조
person.run {
println("이름 : ${name}") //this.name과 동일
}
//it로 참조
person.let {
println("이름 : ${it.name}")
}
}
this
run, with, apply 는 Context Object를 "this" 로 참조합니다.
따라서, 람다식 안에서는 일반 클래스 멤버처럼 사용할 수 있습니다.
this는 생략할 수 있지만, 만약 동일한 이름의 멤버가 있을 경우 구별할 수가 없기 때문에, 가급적이면 Context Object에 대해서는 this를 붙여서 사용하는 것이 좋습니다.
class Person (var name: String, var age: Int)
fun main() {
val person = Person("홍길동", 30)
//this로 참조
person.run {
println("이름 : ${this.name}")
}
}
it
let, also 는 Context Object를 "it" 로 참조합니다.
따로 전달 인자명을 지정할 수도 있고, 지정하지 않으면 기본적으로는 "it" 로 접근하게 됩니다.
class Person (var name: String, var age: Int)
fun main() {
val person = Person("홍길동", 30)
//it로 참조
person.let {
println("이름 : ${it.name}")
}
//전달 인자명 지정해서 참조
person.let { value ->
println("이름 : ${value.name}")
}
}
Return Value
- apply, also는 Context Object를 반환
- let, run, with는 람다식 결과를 반환
Context Object
apply, also의 반환 값은 Context Object 객체 자체입니다.
그렇기 때문에, 체인 형식으로 계속적인 호출이 가능하고,
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()
Context Object를 반환하는 함수의 return문에도 사용할 수 있습니다.
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
}
val i = getRandomInt()
Lambda Result
let, run, with는 람다식 결과를 반환합니다.
그렇기 때문에 결과를 변수에 할당하거나, 결과에 대해 추가적인 작업 등을 수행할 때 사용할 수 있습니다.
val numbers = mutableListOf("one", "two", "three")
val addNumbersList = numbers.run {
add("four")
add("five")
}
또한, 반환 값을 무시하고 바로 람다식을 사용하여, 임시 범위를 만들어서 사용할 수도 있습니다.
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
val firstItem = first()
val lastItem = last()
println("첫번째 항목: $firstItem, 마지막 항목: $lastItem")
}
Functions
이제 그럼, 각 Scope Function들에 대한 설명과 권장하는 사용 케이스 및 사용 스타일에 대해서 알아보도록 하겠습니다.
let
- Context Object : it
- Return Value : lambda result
객체 결과값에 하나 이상의 함수를 호출하는 경우 사용합니다.
/** let 안썼을 때 */
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)
/** let 사용 시 */
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let {
println(it)
// 추가적인 함수 호출 가능
}
또한, let은 null이 아닌 값으로만 코드 블록을 실행시키고 싶을 때 자주 사용됩니다.
null이 아닌 객체에 대해 작업을 수행하려면 안전한 호출 연산자(?.) 를 let에 사용하도록 합니다.
val str: String? = "Hello"
val length = str?.let { //안전한 호출 Safe Call
println("let() 호출 $it")
}
with
- Context Object : this
- Return Value : lambda result
with는 이미 생성된 Context Object 객체를 인자로 받아서 사용하는 것이 효율적일 때는 with를 사용하면 더 좋습니다.
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' 는 ${this} 로 참조합니다.")
println("${size}개의 요소를 포함합니다.")
}
val numbers = mutableListOf("one", "two", "three")
val firstAndLast = with(numbers) {
"첫번째 요소는 ${first() 입니다.}," +
"마지막 요소는 ${last() 입니다.}"
}
println(firstAndLast)
run
- Context Object : this
- Return Value : lambda result
with와 비슷한 역할로, 이미 생성된 Context Object 객체를 사용할 때 호출하며, with와는 전달받는 위치가 다릅니다.
그리고, 가장 중요한 차이점은 앞에 Safe Call (?.)을 붙여서 null 체크까지 할 수 있기 때문에, with보다는 run이 더 자주 사용되는 이유 중 하나라고 할 수 있습니다.
/** 기본 코드 */
val point = Point()
val width = point.x * 0.5
/** run() 사용 코드 */
val width = run {
val point = Point()
point.x * 0.5
}
val point = Point()
val width = point.run {
x * 0.5
}
imageView.layoutParams.run {
width = 400
height = 200
}
apply
- Context Object : this
- Return Value : context object
apply는 보통 객체 초기화 시에 가장 많이 사용됩니다.
val person = Person("홍길동").apply {
age = 30
}
also
- Context Object : it
- Return Value : context object
also는 기존 객체를 수정하거나 변경하지 않고, 디버깅을 위한 로깅 등의 추가적인 부가 작업을 하려고 할 때 사용합니다.
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("새 항목 추가하기 전 리스트 요소들: $it") }
.add("four")
정리
Function | Context Object | Return Value |
let | it | Lambda result |
run | this | Lambda result |
with | this | Lambda result |
apply | this | Context Object |
also | it | Context Object |
'코틀린' 카테고리의 다른 글
코틀린(Kotlin) - 데이터 클래스와 클래스 위임(by) (0) | 2020.03.03 |
---|---|
코틀린(Kotlin) - 생성자와 프로퍼티를 갖는 클래스 선언 (0) | 2020.03.01 |
코틀린(Kotlin) - 클래스 계층 정의 (0) | 2020.02.26 |
코틀린(Kotlin) - 리팩토링 : 로컬 함수와 확장 함수로 코드 중복 없애기 (0) | 2020.02.19 |
코틀린(Kotlin) - 확장 함수 만들기 (2) | 2020.02.17 |