BigJeon Android 개발 블로그
코루틴 사용을 위한 Scope함수에 대하여 알아보자! 본문
코루틴 함수란 비동기 처리를 쉽게 해주기 위한 방법이다.
이름 때문에 코틀린용 방법이라 오해하기 쉽지만 다른 언어에서도 상당히 많이 쓰이는 방법중 한가지이다.
Co + routine으로 협력을 의미하는 Co와 반복을 의마하는 routine을 합친 이름을 생각해보면 코틀린의 코랑은 다른 의미임을 알 수 있다.
오늘은 코루틴을 다뤄보기 전에 코틀린으로 작성한 코루틴에서 쓰이는 Scope함수에 대하여 알아 보고자 한다.
우선
Scope함수란 무엇일까?
남자들에게 Scope라 함은 배율 생각이 날것이다.(나만 그런가...?)
코틀린의 표준 라이브러리의 경우 객체의 컨텍스트 내에서 코드를 실행 만을 위해 제공되는 여러 함수들이 있는데,
이러한 함수들을 람다식으로 표현할때 Scope(범위)를 형성합니다. 이 범위 안에서는 객체의 이름없이 객체에 접근 할 수 있는데,
이러한 함수를 Scope함수라고 합니다.
scope 함수에는 let, run, with, apply, also의 5가지가 있습니다.
하지만 이 5가지 기능들은 비슷하지만 다른 기능들을 수행하여 굉장히 헷갈리는 경우가 많은데, 이번 포스팅을 통해 좀더 세밀하게 다뤄 볼까하고자 준비했습니다.
1. let
fun <T, R> T.let(block: (T) -> R): R
let 함수는 매개변수화된 타입 T의 확장 함수입니다. 자기 자신을 받아서 R을 반환하는((T) -> R) 람다 식을 입력으로 받고, 블럭 함수의 반환값 R을 반환합니다.
(확장 함수란 기존의 클래스에 추가적인 메서드를 붙인것을 말한다.)
val Jeon = Person("BIGJEON", 25)
val Programmer = Jeon.let {
it.Name = "Me"
it.Age = 5
it
}
결과값 : Person(Name=Check, Age=12)
또한 let특성상 T?.let{}의 경우로 let을 사용했을때 let의 블럭안에는 Non_Null만 들어올 수 있는데, 이를 이용하여 자주 Null_Check를 위해 이용하게 됩니다, 하지만 이러한 사용시 주의해야 할 사항이 있습니다.
유의해야 할 상황으로는
불변 변수를 인자로 받아 null check를 시도하는 것인데,
fun CheckNull(str: String?) {
str?.let { ... }
}
위의 코드는 null이라면 ~~한다 라는 코드인데, 위의 let함수를 자바로 변환하면
public final void CheckNull(@Nullable String str) {
if (str != null) {
boolean var4 = false;
....
}
}
위와 같은 코드로 바뀝니다, 자바 코드로 보면 결규 if (str != null) 체크한것과 같습니다. 오히려 이러한 경우 쓸데 없는 추가적인 변수만생겨 오히려 추가적인 작업을 해주는 상황이 되어버린겁니다.
이러한 경우만 조심하여 사용하면 되는 Scope함수 let이였습니다.
2. with
fun <T, R> with(receiver: T, block: T.() -> R): R
with함수의 경우 일반 함수 이기때문에 직접 객체를 입력 받고, 객체를 사용하기 위한 두번째 파라미터를 입력받습니다.
성공적으로 객체를 입력 받았을경우 this를 사용하지 않고 객체에 접근 할 수 있습니다.
val Jeon = Person("BIGJEON1", 25)
with(Jeon){
println(Name)
}
실행 결과 : BIGJEON1
위 예제처럼 this를 사용하지않고 바로 Person의 프로퍼티 Name을 출력하는 모습을 확인 할 수 있습니다.
With의 경우 Non_null의 객체를 입력 받고, 반환값(Return)이 없을 경우 사용합니다.
따라서 객체의 여러가지 함수를 호출 할 때 사용합니다.
3. run
run의 경우 위와 같이 2가지 형태가 존재하는데,
1.
fun <T, R> T.run(block: T.() -> R): R
2.
fun <R> run(block: () -> R): R
1번의 경우 위의 with함수와 비슷하지만 다른점은 확장함수라는 점입니다.
확장 함수이기 떄문에 Non_null타입의 객체를 입력받고, 값에 대한 계산을 하거나, 여러가지 변수들의 범위를 지정하는 등의 용도로 쓰입니다.
2번의 경우 받는 입력값도 아니고 확장함수도 아니다. 2번의 run의 경우 어떠한 객체를 생성할 떄 주로 사용됩니다.
여러 객체를 생성할때 코드의 가독성을 올리기 위해 사용되곤 합니다.
val RunCheck = run {
val Name = "Run"
val Age = 12
Person(Name, Age)
}
val AgeUp = RunCheck.run {
++Age
}
실행결과 : Person(Name=Run, Age=13) , 13
위의 예제를 보면 매처음 2번의 run을 이용해 RunCheck라는 Person객체를 생성했고, 그 아래 1번의 run을 이용하여 나이를 하나 올려주었다.
4. apply
fun <T> T.apply(block: T.() -> Unit): T
apply의 경우 run과 같이 확장함수이고, Non_Null Type의 객체를 입력 받습니다. 1번의 run과 다른점으로는 반환값을 정해주는 것이 아니라 객체를 생성한후 생성한 객페를 반환 해준다는 점에서 차이가 있습니다.
val Jeon = Person("BIGJEON1", 25)
val LetCheck = Jeon.apply {
Age = 26
}
println("${Jeon}")
실행 결과 : Person(Name=BIGJEON1, Age=26)
위의 예제에서 알 수 있듯이 let을 통해 Age를 26으로 바꾸어 주었고 변경된 값이 Jeon객체에 저장되어 출력되는것을 볼수있습니다.
Jeon객체가아닌 LetCheck를 출력하게 되면 반환값이 없어 Unit타입을 Kotlin.Unit이라는 값이 출력하게 됩니다.
5. also
fun <T> T.also(block: (T) -> Unit): T
also의 경우 위의 apply와 비슷한 기능을 수행하는데 apply와 같이 확장 함수이며, 입력받은 객체를 반환하는 것 까지는 동일하다.
하지만 람다 형식으로 객체를 입력 받지 않기 때문에 it을 이용하여 객체에 접근해야 합니다.
val Jeon = Person("BIGJEON1", 25)
val Check = Jeon.also {
it.Age = 12
it.Name = "Check"
}
println("${Check}")
실행 결과 : Person(Name=Check, Age=12)
위의 apply와 다른점은 위의 예제에서도 알 수 있듯이 입력받은 객체를 받환하기 떄문에 반환값이 존재합니다.
따라서 위의 apply를 출력했을때 나왔던 Kotlin.Unit과는 다르게 값이 바뀐 Person객체가 출력되는것을 알 수 있습니다.
또한 it을 사용하여 객체에 접근하였기 때문에 객체의 속성을 바꾸거나 사용하지 않는 상황에 이용합니다.
데이터 유효성을 확인하거나, 디버그, 로깅 등의 부가적인 목적으로 사용할 때 적합니다.
이로써 Scope함수 5가지를 오늘 포스팅 해보았는데, 정말 용도가 비슷하기 떄문에 헷갈리기 쉬운 함수인거 같습니다.
그래도 특징을 잡아 알아두면 코루틴에 대하여 공부할때 큰 도움이 될거 같으니 미리미리 공부해 두면 좋을거 같습니다.
그럼 다음 포스팅은 코루틴으로 돌아오겠습니다!
*잘못된 부분에 대한 지적은 항상 감사하게 받겠습니다*
'AOS - Kotlin' 카테고리의 다른 글
안드로이드(Kotlin) 내장 카메라로 찍은 사진 가져오기 (0) | 2021.05.26 |
---|---|
안드로이드(Ko)_옵저버 (설명, 예시)_EventListener (0) | 2021.04.03 |
안드로이드(Ko) RecyclerView 사용 예제 (0) | 2021.04.01 |
안드로이드(코) extension대체.ViewBinding 사용하기 (0) | 2021.03.23 |
안드로이드(코) 익스텐션이 deprecated 이후 findViewbyId 사용하기 (0) | 2021.03.22 |