정상에서 IT를 외치다

[Android, Kotlin] 코틀린의 run, with, apply, let, also 정리 본문

안드로이드

[Android, Kotlin] 코틀린의 run, with, apply, let, also 정리

Black-Jin 2019. 3. 18. 00:22
반응형


안녕하세요. 블랙집입니다.


그동안 코틀린을 사용하면서 run, with, apply, let, also 를 사용했지만 내용을 한번 정리해 보면 좋을 것 같아 간략히 포스팅을 합니다.

this

runwith, and apply refer to the context object as a lambda receiver - by keyword this. Hence, in their lambdas, the object is available as it would be in ordinary class functions. In most cases, you can omit this when accessing the members of the receiver object, making the code shorter. On the other hand, if this is omitted, it can be hard to distinguish between the receiver members and external objects or functions. So, having the context object as a receiver (this) is recommended for lambdas that mainly operate on the object members: call its functions or assign properties.


apply , run, with 함수의 블록 안에서는 수신 객체를 this 로 표현됩니다.



1. apply

private val adapter = MainAdapter().apply {
setClickListener(this@MainActivity)
}

위 예제는 어댑터를 생성함과 동시에 클릭 리스너를 초기화 해주는 코드입니다. 특정 객체를 생성함과 동시에 초기화 해줄 때 매우 유용하게 사용합니다. 



2. run


apply 함수와 유사하나 apply 함수는 객체를 생성함과 동시에 연속된 작업을 수행할 때 사용하고  run 함수는 이미 생성된 객체의 메서드나 필드를 연속적으로 호출할 때 사용합니다.

recyclerView.run {
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = this@MainActivity.adapter
}

리사이클러뷰의 레이아웃매니저와 어댑터를 연속적으로 호출하는 예 입니다.

recyclerView?.run {
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = this@MainActivity.adapter
}

또한 let 함수와 마찬가지로 ?를 사용하여 널 안정성 검사를 할 수 있습니다.



3. with


run 함수와 기능은 동일하나 리시버로 전달할 객체가 어디에 위치하는지가 다릅니다.

with(recyclerView) {
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = this@MainActivity.adapter
}

여기에 with, let 함수를 사용하여 run 과 동일한 기능을 수행할 수 있습니다. 

recyclerView?.let {
with(it) {
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = this@MainActivity.adapter
}
}


it

In turn, let and also have the context object as a lambda argument. If the argument name is not specified, the object is accessed by the implicit default name itit is shorter than this and expressions with it are usually easier for reading. However, when calling the object functions or properties you don't have the object available implicitly like this. Hence, having the context object as it is better when the object is mostly used as an argument in function calls. it is also better if you use multiple variables in the code block.


let, also 함수의 블록 안에서는 수신 객체를 it 으로 표현됩니다.



4. let


it 을 사용한 경우

intent.getSerializableExtra(KEY_USER)?.let {
if(it is User) {
// kotlin 에서는 자동으로 형 변환이 이뤄집니다.
user = it
}
} ?: throw IllegalAccessException("intent is null")

단일 지역 변수를 지정한 경우

intent.getSerializableExtra(KEY_USER)?.let {userData ->
if(userData is User) {
// kotlin 에서는 자동으로 형 변환이 이뤄집니다.
user = userData
}
} ?: throw IllegalAccessException("intent is null")

이미 생성된 객체를 블록으로 감싸 그 안에서 단일 지역 변수로 사용할 수 있습니다. 또한 ? 와 함께 사용하여 널 안정성 검사를 할 수 있습니다.


5. also


apply 함수와 마찬가지로 객체를 반환하며 let 과 동작이 매우 유사합니다. 하지만 let 에서는 내부 결과를 변화 시킬 수 있지만 also 에서는 변화 시킬 수 없습니다, 

private val adapter = MainAdapter().also {
it.setClickListener(this@MainActivity)
}

apply 함수 대신 also 를 사용 할 수 있다

val original = "abc"
// Evolve the value and send to the next chain
original.let {
println("The original String is $it") // "abc"
it.reversed() // evolve it as parameter to send to next let
}.let {
println("The reverse String is $it") // "cba"
it.length // can be evolve to other type
}.let {
println("The length of the String is $it") // 3
}
// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
println("The original String is $it") // "abc"
it.reversed() // even if we evolve it, it is useless
}.also {
println("The reverse String is ${it}") // "abc"
it.length // even if we evolve it, it is useless
}.also {
println("The length of the String is ${it}") // "abc"
}
// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain
original.also {
println("The original String is $it") // "abc"
}.also {
println("The reverse String is ${it.reversed()}") // "cba"
}.also {
println("The length of the String is ${it.length}") // 3
}


위와 같이 내부 결과를 변화 시킬 수 없다.


Return value

The scope functions differ by the result they return:

  • apply and also return the context object.
  • letrun, and with return the lambda result.

These two options let you choose the proper function depending on what you do next in your code.


apply, also 는 객체를 리턴합니다.


let, run, with 는 람다 결과를 리턴합니다.





<참고자료>

Scope Functions

kotlin standard function


코틀린의 유용한 함수

apply, with, let, also, run 은 언제 사용하는가?


코틀린 스코프와 고차 함수

반응형
Comments