let, with, run, apply, also
코틀린에는 이렇게 생긴 확장 함수들이 있다. 기능은 객체를 사용할 때 명령문들을 블럭{}으로 묶어서 간결하게 사용할 수 있게 해 주고 스코프 함수(Scope Functions)이다
# let
매개 변수화 된 타입 T의 확장 함수로, 자기 자신을 받아서 반환하는 람다 식의 형태이다.
let 함수를 호출하는 객체를 블록의 인자로 넘기고, 블록의 결괏값을 반환한다.
fun <T, R> T.let(block: (T) -> R): R
- let 함수 사용하기 전 코드
data class Student (var name : String, var age : Int)
val student = Student("",0)
student.name = "Yeom"
student.age = 23
println("$student")
// 출력 : Student(name=Yeom, age=23)
- let 함수 사용
data class Student (var name : String, var age : Int)
val student = Student("",0)
// 방법 1 해당 객체를 it 키워드로 호출
val result = student.let{
it.name = "Yeom"
it.age = 23
it // (T)->R 부분에서의 R에 해당하는 반환값.
}
// 방법 2 인자의 이름을 직접 명령
val result2 = student.let{
resultStr ->
resultStr.name = "Yeom2"
resultStr.age = 24
resultStr // (T)->R 부분에서의 R에 해당하는 반환값.
}
// 방법 3 반환값 없음
val result2 = student.let{
it.name = "Yeom"
it.age = 23
// (T)->R 부분에서의 R에 해당하는 반환값 없음.
}
println("$result")
println("$result2")
println("$result3")
// 출력 : Student(name=Yeom, age=23)
// 출력 : Student(name=Yeom2, age=24)
// 출력 : kotlin.Unit
블록 마지막 return 값에 따라 let의 return 값 형태도 달라진다.
그리고 T?.let { } 형태에서의 블록 안에는 non-null 만 들어올 수 있어서 non-null 체크 시에 유용하게 사용할 수 있다.
// null인 변수 name
var name: String? = null
// name가 null이 아닐 경우 작업 수행 (기존 방식)
if (null != obj) {
Toast.makeText(this, "$name", Toast.LENGTH_LONG).show()
}
// name가 null이 아닐 경우 작업 수행 (Safe calls + let 사용)
name?.let {
Toast.makeText(this, it, Toast.LENGTH_LONG).show()
}
# with
with은 일반 함수이다. 파라미터로 직접 객체를 입력받고, 객체를 사용하기 위한 람다 블록을 받는다.
fun <T, R> with(receiver: T, block: T.() -> R): R
이렇게 receiver로 객체를 입력받으면, it이나 this 등 키워드 없이 객체의 속성을 참조하거나 변경할 수 있다.
사용 규칙으로는 Non-Nullable 객체이여야 한다. / 결과가 필요하지 않은 경우.
data class Student (var name : String, var age : Int)
val student = Student("Yeom", 23)
with(student) {
println(name)
println(age)
// 자신을 참조해야 하는 경우 this 키워드 사용
}
// 출력 : Yeom
// 출력 : 23
이런 식으로 객체의 함수나 속성을 여러 번 호출할 때 코드들을 그룹핑하는 용도로 활용할 수 있다.
# run
run은 두 가지 형태로 선언되어 있다.
1. fun <T, R> T.run(block: T.() -> R): R
with와 다른 점이라면, T의 확장 함수로 선언되어 있다는 점이다.
확장 함수이기 때문에 with와 다르게 Safe Call을 붙인다면 null 객체가 들어와도 non-null 검사를 하고 실행할 수 있다.
data class Student (var name : String, var age : Int)
val student = Student("Yeom", 23)
val ageNext = student.run {
++age // Return
}
println("$ageNext")
// 출력 : 24
또한, 마지막 실행문의 결과를 반환하게 된다.
따라서, 객체의 특성이나 메소드 등을 활용하여 어떤 값을 계산할 필요가 있거나, 여러 개의 지역변수 범위를 제한하고자 할 때 사용한다.
2. fun <R> run(block: () -> R): R
이것은 확장 함수가 아니고, 블록에 입력값도 없다. 객체 속성을 이용하려는 상황에 사용되는 함수가 아니고, 어떤 객체를 생성하기 위한 실행문들을 하나로 묶어 가독성을 높여준다.
data class Student (var name : String, var age : Int)
val student = run {
val name = "Yeom"
val age = 23
Student(name,age) // Return
}
// Student에 담겨있는 값 name = "Yeom", age = 23
# apply
apply는 T의 확장 함수이고, 블록 함수의 입력을 람다 리시버로 받았기 때문에 블럭 안에서 객체의 프로퍼티를 호출할 때 it이나 this를 사용할 필요가 없다. run과 유사하지만 블록에서 return 값을 받지 않으며 자기 자신인 T를 반환한다는 점이 다르다.
fun <T> T.apply(block: T.() -> Unit): T
data class Student (var name : String, var age : Int)
val student = Student("",0)
val result = student.apply {
name = "Yeom"
age = 23
}
println("$result")
// 출력 : Student(name=Yeom, age=23)
앞에서 살펴본 let, with, run 은 모두 맨 마지막 반환 되는 값은 R이었다. 하지만 apply와 아래에서 살펴볼 also는 T를 반환한다.
객체의 함수를 사용하지 않고 자기 자신을 다시 반환할 때에 사용되기 때문에, 객체의 초기화나 변경 시에 주로 사용된다.
# also
also는 T의 확장 함수이고, 블록 함수의 입력으로 람다 리시버를 받지 않고 this로 받았다. apply와 마찬가지로 T를 반환한다.
fun <T> T.also(block: (T) -> Unit): T
data class Student (var name : String, var age : Int)
val student = Student("",0)
val result = student.also {
it.name = "Yeom"
it.age = 23
}
println("$result")
// 출력 : Student(name=Yeom, age=23)
블럭 함수의 입력으로 T를 받았기 때문에 it을 사용해 프로퍼티에 접근하는 것을 볼 수 있다. 그래서 객체의 속성을 전혀 사용하지 않거나 변경하지 않고 사용하는 경우에 also를 사용한다.
객체의 데이터 유효성을 확인하거나, 디버그, 로깅 등의 부가적인 목적으로 사용할 때에 적합하다.
also()가 apply() 함수와 다른 점은 객체를 넘겨받는 방식이다.
also() 함수는 it을 통해 멤버에 접근한다. 하지만 apply()에서는 함수 타입에 리시버가 있기 때문에 this를 생략하고 멤버 이름만 사용하고 있다.
참고 : https://blog.yena.io/studynote/2020/04/15/Kotlin-Scope-Functions.html
https://velog.io/@ejjjang0414/%EC%BD%94%ED%8B%80%EB%A6%B0-%EB%8C%80%ED%91%9C%EC%A0%81%EC%9D%B8-%ED%91%9C%EC%A4%80%ED%95%A8%EC%88%98-let-also-apply-run-with-%EC%9D%98-%EC%B0%A8%EC%9D%B4
'Kotlin 공부 노트' 카테고리의 다른 글
프래그먼트(Fragment) with Kotlin 알아보기! (0) | 2022.02.10 |
---|---|
코틀린의 접근 제한자(Kotlin's Visibility Modifier) (0) | 2022.02.06 |
리사이클러뷰(RecyclerView)만들어보기 (0) | 2021.12.24 |
코틀린의 배열/리스트 (0) | 2021.12.15 |
코틀린의 기본 문법 2(함수,람다,When,생성자) (0) | 2021.12.15 |