코틀린(Kotlin)

코틀린 Scope Functions[2] - [ let, run, with, apply, also ] 사용 예제 + takeIf, takeUnless

알통몬_ 2019. 7. 16. 16:30
반응형


공감 및 댓글은 포스팅 하는데

 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 

도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 

만들어 나가겠습니다^^

 


지난 포스팅에서 Scope Functions 에 대해 공부했는데요.

2019/07/16 - [코틀린(Kotlin)] - 코틀린 Scope Functions - [ let, run, with, apply, also ]


이번 포스팅에서는 각 함수의 사용 예제에 대해 보겠습니다.


=======================================================

let

context object를 it argument로 사용할 수 있습니다.

반환 값은 람다 결과입니다.

call chains의 결과에서 하나 이상의 함수를 호출하는데 사용할 수 있습니다.

// 예제 1
val numbers = mutableListOf("one", "two", "three", "four", "five", "six")
val result = numbers.map { it.length }.filter { it > 3 }
println(result)

numbers.map { it.length }.filter { it <= 3 }.let { println(it) }

// 람다 대신에 메소드 참조를 사용할 수도 있습니다.
numbers.map { it.length }.filter { it <= 3 }.let(::println)



// 예제 2
fun processNonNullString(str: String){}

val str: String? = "Hello"
val length = str?.let {
println("let() called on $it")
processNonNullString(it)
it.length
}


// 예제 3
val numbers2 = listOf("one", "two", "three", "four")
val modifiedFirstItem = numbers2.first().let { firstItem ->
println("The first item of the list is '$firstItem'")
if(firstItem.length >= 5) firstItem else "!$firstItem!"
}.toUpperCase()
println("First item after modifications: '$modifiedFirstItem'")

=======================================================



=======================================================

with

확장함수가 아닙니다. context object는 argument로 사용되고 람다의 내부에서는

receiver(this)로 사용됩니다. 반환 값음 람다의 결과값입니다.


공식 문서에서는 with 함수는 람다의 결과를 제공하지 않고 context object에서

함수를 호출할 것을 권장한다고 합니다.

fun main() {

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' is called with argument numbers")
println("It contains $size elements")
}
val numbers2 = mutableListOf("one", "two", "three")
val firstAndLast = with(numbers2) {
"The first element is ${first()} and the last element is ${last()}"
}

println(firstAndLast)
}

with 의 argument 가 this 되게 때문에 해당 argument 가 가지는 멤버를 바로

호출할 수 있습니다. 위 예제에 경우 MutableList() 이기 때문에

size, fist(), last() 등의 멤버를 호출했습니다.

=======================================================


=======================================================

run

context object 가 receiver 로 사용됩니다. 반환 값은 람다의 결과 값입니다.

run은 with와 같지만, let처럼 호출합니다.

run은 context object 의 초기화와 계산이 같이 들어갈 때 사용하면 유용합니다.


class MultiportService(var url: String, var port: Int) {
fun prepareRequest(): String = "Default request"
fun query(request: String): String = "Result for quest '$request'"
}

fun main() {

val service = MultiportService("https://www.abcdefg.com", 80)

val result = service.run {
port = 8000
query(prepareRequest() + "to port $port")
}

val letResult = service.let {
it.port = 8080
it.query(it.prepareRequest() + "to port ${it.port}")
}

println(result)
println(letResult)


}


그리고 비확장 함수로도 사용할 수 있습니다.

val hexNumberRegex = run {
val digits = "0-9"
val hexDigits = "A-F-a-f"
val sign = "+-"

Regex("[$sign]?[$digits$hexDigits]+")
}

for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) {
println(match.value)
}

실행은 각자 ㅎ

=======================================================


=======================================================

apply

data class ApplyUser(var name: String, var age: Int = 0, var country: String = "")

fun main() {

// Context object를 receiver(this)로 사용합니다.
// 반환 값은 사용된 object 자기 자신입니다.

val thomas = ApplyUser("Thomas Park").apply {
age = 28
country = "Republic of Korea"
}

println(thomas)

}

=======================================================


=======================================================

also

fun main() {


// context object는 argument(it) 으로 사용됩니다. 반환값은 apply 와 마찬가지로 자기 자신입니다.
// also 는 context object 를 argument로 취하는 작업을 할 때 사용하는 것이 좋습니다.

val numbers = mutableListOf("one", "two", "three")
numbers.also { println("The list element before adding new one $it") }.add("four")

}
=======================================================



Function Selection
함수 간 차이들

 Function

Object reference 

return value 

Is extension function 

 let

it 

 Lambda result 

Yes 

 run 

this 

 Lambda result  

Yes 

 ryn 

 -  

 Lambda result 

No: called without the context object 

 with

 this 

 Lambda result 

No: takes the context object as an argument. 

 apply  

 this 

 Context Object 

Yes 

 also 

 it 

 Context Object 

Yes 


사용 목적에 따른 간단한 사용 가이드

- null 이아닌 object를 람다 실행 : let

- 로컬 범위에서 변수로 표현식 소개 : let

- object 구성 및 계산 결과를 얻을 때 : run

- 표현식이 필요한 구문 실행 : run

- 추가적인 효과 : also

- object 의 함수를 묶어서 호출할 때 : with


지금까지 소개한 범위 함수들은 서로 중복되는 부분도 있기에 여러분들이
하는 프로젝트에 맞게 사용하시며 될 거 같습니다.

이상입니다. 감사합니다.

=====================================================
+ takeIf, takeUnless

예제를 보면알 수 있기에 따로 설명은 생략하겠습니다.

간단한 예제)

fun main() {

val number = Random.nextInt(100)

val evenOrNull = number.takeIf { it % 2 == 0 }
val oddOrNull = number.takeUnless { it % 2 == 0 }

println("evenOrNull = $evenOrNull | oddOrNull = $oddOrNull")


val str = "Hello"
val caps = str.takeIf { it.isNotEmpty() }?.toUpperCase()
println(caps)
}



반응형