728x90
- 코틀린의 표준 라이브러리에는 객체의 컨텍스트 내에서 코드 블록을 실행하기 위해서만 존재하는 몇 가지 함수가 포함되어 있고, 이를 스코프 함수라고 한다.
- 스코프 함수를 제대로 사용하면, 변수 선언이 없어지며, 코드를 더 간결하고 읽기 쉽게 만든다.
- 스코프 함수의 코드 블록 내부에서는 변수명을 사용하지 않고도 객체에 접근할 수 있는데, 그 이유는 수신자 객체에 접근할 수 있기 때문이다.
- 수신자 객체는 람다식 내부에서 사용할 수 있는 객체의 참조이다.
- 스코프 함수를 사용하면, 수신자 객체에 대한 참조로 this 또는 it를 사용한다.
스코프 함수 종류
총 5개의 유용한 스코프 함수를 제공하며, 각 스코프 함수들은 유사한 기능을 제공한다.
| 함수명 | 수신자 객체 참조 방법 | 반환 값 | 확장함수 여부 |
| let | it | 함수의 결과 | O |
| run | this | 함수의 결과 | O |
| with | this | 함수의 결과 | X |
| apply | this | 컨텍스트의 객체 | O |
| alse | it | 컨텍스트의 객체 | O |
let
fun main() {
val str: String? = "안녕"
val result: Int? = str?.let {
println(it)
/*
val abc: String? = "abc"
abc?.let {
val def: String? = "def"
//함수 내부에 함수가 매번 쓰이니, 가독성 측면에서 그렇게 좋지는 않다.ㄴ
def?.let {
println("abcdef가 null 아님")
}
}
*/
val abc: String? = "abc"
val def: String? = "def"
//많이 중첩되는 경우는 이전의 If/else 를 쓰는것이 좋다
if (!abc.isNullOrBlank() && !def.isNullOrBlank()) {
println("abcdef가 null 아님")
}
1234 //return 키워드는 없지만, 마지막 쓴 값이 리턴이 된다.
}
println(result)
}
- null이 아닌 경우 사용될 로직을 작성하고, 새로운 결과를 반환하고 싶을때, 사용한다
- null이 아닌 경우, 로직이 실행한다
- let 함수 내부의 마지막 코드를 결과로 반환한다
- let을 사용할 때, 호출이 중첩이된다면, 코드가 되려 복잡해지므로, if/else를 사용하는 것이 더 좋다.
run
//Run : 수신 객체의 프로퍼티를 구성하거나,새로운 결과를 반환하고 싶을 때 사용
class DatabaseClient {
var url: String? = null
var username: String? = null
var password: String? = null
//DB에 접속하고 Boolean 결과를 반환
fun connect(): Boolean{
println("DB 접속 중...")
Thread.sleep(1000)
println("DB 접속 완료")
return true
}
}
fun main() {
/*
val config = DatabaseClient()
config.url = "localhost:3306"
config.username = "mysql"
config.password = "1234"
val connected = config.connect()
println(connected)
*/
/*
//let으로 변환도 가능
val connected: Boolean = DatabaseClient().let {
it.url = "localhost:3306"
it.username = "mysql"
it.password = "1234"
it.connect()
}
*/
val connected: Boolean = DatabaseClient().run {
//변수의 참조를 매번 사용할 필요 없이, 사용할 수 있다.
url = "localhost:3306" //수신자 객체가 DatabaseClient 이기 때문에 this 생략 가능
username = "mysql"
password = "1234"
connect()
}
println(connected)
}
- 수신 객체의 프로퍼티를 구성하거나, 새로운 결과를 반환하고 싶을 때 사용한다.
- run을 사용하면, 변수의 참조를 매번 사용할 필요 없이, 가독성 좋게 코드를 작성할 수 있다.
- let을 사용하여도 같은 동작을 작성할 수 있지만, 매번 it키워드가 들어가게 되므로, run을 사용하는 편이 더 좋다.
with
fun main() {
val str = "안녕하세요"
val length = with(str) {
//println("length= $length")
length //함수의 마지막에 쓴 결과를 반환 한다
}
println(length)
//with는 확장함수가 아니다 -> 파라미터에 참조를 넣는다
val result:Boolean = with(DatabaseClient()) {
url = "localhost:3306"
username = "mysql"
password = "1234"
connect()
}
println(result)
}
- 결과 반환없이 내부에서 수신 객체를 이용해 다른 함수를 호출하고 싶을 때 사용한다.
- 확장 함수가 아닌, 파라미터에 수신 객체를 참조로 넣어 전달한다.
- with, run으로도 같은 동작을 하는 함수를 작성할 수 있다.
apply
fun main() {
//apply 같은 경우 마지막에 호출한 함수가 아닌 본인을 반환한다
/*
val client = DatabaseClient().apply {
//초기화나 같은 동작에서 많이 사용한다
url = "localhost:3306"
username = "mysql"
password = "1234"
connect()
}
//println(client)
client.connect().run {
println(this)
}
*/
DatabaseClient().apply {
//초기화나 같은 동작에서 많이 사용한다
url = "localhost:3306"
username = "mysql"
password = "1234"
connect()
}.connect()
.run { println(this) }
}
- 수신 객체의 프로퍼티를 구성하고, 수신 객체를 결과 그대로 반환하고 싶을 때 사용한다.
- let, run with 함수의 결과가 반환되는 것에 반해 apply는 수신 객체 그대로 반환한다.
- 메서드 체이닝을 통해 한번에 작성할 수 있지만, 가독성 측면에서 좋지 않다.
also
//alse : 부수 작업을 수행하거나, 전달받은 객체를 그대로 반환할 때 사용한다
class User(val name: String, val password: String) {
fun validate(){
if(name.isNotEmpty() && password.isNotEmpty()){
println("검증 성공")
}else{
println("검증 실패!")
}
}
fun printName() = println(name)
}
fun main() {
//apply 사용 x
val user: User = User(name = "tony", password = "1234")
user.validate()
//apply 사용
User(name = "tony", password = "1234").also {
it.validate()
it.printName()
}
}
- 부수 작업을 수행하고 전달받은 수신 객체를 결과 그대로 반환하고 싶을 때 사용한다.
스코프 함수 사용 시 주의할 점
fun main() {
/*
val this:String? = null //this는 키워드라 다른 곳에서 사용 안된다.
val it: String? =null //it은 사용가능 //소프트 예약어
*/
val hello = "hello"
val hi = "hi"
/*
hello.let {
println(it.length)
hi.let {
println(it.length)//해당 it는 해당 컨텍스트 it인지, 외부의 it인지 알기 힘드므로, 중첩된 코드는 사용하지 말자
}
}
*/
hello.let { a: String ->
println(a.length)
hi.let {b: String -> //변수를 사용하는 방식으로 하여, 혼동이 없도록 하자
println(b.length)
}
}
}
- 스코프 함수는 모두 기능이 유사해, 실무에선 섞어 쓰는 경우가 많다.
- this는 키워드(사전에 정의된 예약어) 임으로 다른 의미로 사용할 수 없지만, it는 특정 용도에서만 작동하는 소프트 키워드이기 때문에 다른 용도로 사용할 수 있다.
- 중첩으로 사용된 경우 this, it에 대해 혼동되므로, 변수를 사용하는 방식으로 혼동되지 않게 사용하도록 하자
- 중첩 함수 내에서 외부 함수에 대해 it로 접근이 불가능하다
728x90
'실무 프로젝트로 배우는 Kotlin & Spring > 코틀린 고급' 카테고리의 다른 글
| 람다로 프로그래밍하기 (0) | 2022.10.22 |
|---|---|
| 고급 예외처리 (0) | 2022.10.22 |
| 페어와 구조분해할당 (0) | 2022.10.16 |
| 지연 초기화 (0) | 2022.10.16 |
| 제네릭 (0) | 2022.10.16 |