이번에는 Scope 함수 라는 것을 정리해 보고자 합니다.

이 함수들은, 객체의 컨텍스트를 유지하면서, 코드 블록을 받아서 실행시키는데요.

let, apply, with, run, also 같이 종류가 무려 5개나 됩니다.

 

이 함수들은 대부분 중요해서 android개발하면서 계속 마주치게 되므로,

잘 정리해서 사용해 보는 것이 좋은데요.

 

이 글에서는 5가지 Scope함수와 더불어 함께 사용할 수 있는 함수인,

takeIf그리고 takeUnless까지 같이 정리해 보겠습니다.

1. Scope Functions

ScopeFunction이라는 함수명에서 알 수 있듯이,

이 함수들을 lambda식을 이용해서 호출하면,

일시적인 Scope(범위)가 생기게 됩니다.

이 범위안에서는 객체에 대해 "it" 혹은 "this"라고 하는 Context Object를 통해서 자유롭게 접근할 수 있게 됩니다.

 

많이 쓰이는 let함수의 코드를 보도록 하겠습니다.

Student객체를 생성하고 let이라는 scope함수를 호출하였습니다.

여기서 객체에 it으로 접근하여 it.age를 print하거나,

객체의 함수를 실행하여 property를 변경하기도 하였습니다.

 

 

이것을 let을 쓰지 않고 코딩해보면 아래와 같은데요.

위의 것이 객체의 사용범위도 더욱 잘 읽히고 좀더 명확하게 보이시나요?

아무래도 다른 코드들과 섞여있을 때 장점이 더 명확하게 보이기는 할 것 같네요.

 

 

Scope함수의 대표주자인 let을 보았구요.

이제는 각각의 함수를 구분하는 기준을 보면서 조금씩 알아보도록 하겠습니다.

 

2. Context Object와 Return값에 따른 구분

아래 표를 보면 각각의 함수가 어떻게 다른 context object를 사용하고,

return값은 어떻게 다른지 알 수 있습니다.

  context object return
run this lambda result
with this lambda result
apply this context object
also it context object
let it lambda result

각각에 대한 구체적인 구분은 아래에서 하나씩 하겠지만,

이 함수들의 context object가 무엇이고, return값이 무엇인지를 잘 생각하면,

좀 더 효율적으로 사용할 수 있을 것 입니다.

예를 들어, 객체를 받아서, 어떠한 계산등을 통해 결과 값을 사용해야 하는지,

또는 블록 안에서 객체에 접근해서 객체를 수정하려고 하는지 등에 따라 선택할 함수에 따라 달라지는 것이지요.

 

이제 구체적으로 각각의 함수에 대해서 보도록 하겠습니다.

3. 5가지 함수의 구별

3-1. let

위에서 보았던 let으로 부터 시작해 보겠습니다.

let은 함수를 호출하는 객체를 context object인 it을 통해서 코드블록으로 넘겨주고요,

lamda식의 결과를 return 해 줍니다.

let이 많이 사용되는 두가지 경우는 다음과 같습니다.

 

A. chain operation에서의 사용

아래와 같이 chain operation에서 하나이상의 함수를 사용하기 위해서 사용할 수 있습니다.

아래 코드에서는 print만 사용하였지만 여러 함수를

context object인 it을 통해 사용할 수 있습니다.

 

 

B. non-null value를 가지고 코드블록을 실행시키고자 할 때 사용

'?.let { }' 코드블록 안에는 non-null인 값만 들어올 수 있으므로,

non-null이 필요한 경우에 사용할 수 있습니다.

또한 let은 lamda값의 결과 값을 return하므로,

이 값을 변수에 담아서 어떤 과업을 할 수도 있습니다.

 

아래와 같이 list의 forEach에도 사용해 볼 수 있을 것 같네요.

(물론 list에는 filterNotNull()이라는 메소드가 존재하기 때문에 아래와 같이 사용할 일이 많지는 않겠지요)

 

 

3-2. with

with는 단어에서 알 수 잇듯이, 이 객체를 가지고 다음의 어떤 것을 하기 위한 목적을 가지고 있습니다.

인자로 받는 객체를 코드블록 안에 this라는 context object로 전달하는데요.

lambda의 결과 값을 return해 줍니다.

with의 경우 인자로 객체를 받아서 사용을 하는데요.

인자로 받아서 사용하는 것이 효율적일 때는 with를 사용하면 더 좋습니다.

 

A. 람다식의 결과값을 필요로 하지 않고, 함수 호출들을  grouping해서 사용할 때

 

 

B. 객체가 필요로 하는 값을 계산해 주는 경우

this를 context object로 받는 경우는 생략이 가능하므로,

아래에서는 생략하여 first()와 last()메소드를 이용한 값을 계산하였습니다.

 

 

3-3. run

with와 context object나 return값도 같아서 비슷한 역할을 하지만, 객체를 받는 위치가 다릅니다.

필요에 따라서는 앞에 safeCall(?.)을 붙여서 null이 아닌 값에만 run을 실행할 수 있구요.

이것은 with보다는 run을 더 자주 사용하게 될 이유중 하나가 될 수도 있겠습니다.

 

A. 객체를 초기화하고 return 값의 계산이 필요한 경우

 

 

B.  expression이 필요한 여러줄의 코드를 한번에 처리할 때

 

 

3-4. apply

호출하는 객체를 코드블록안에 context object인 this로 전달을 하고

return값은 object자신입니다.

전달받는 객체의 멤버에 operate하는 것을 주목적으로 하며, 

객체가 return되므로 연산해서 return하고자 하는 값이 없는 경우 사용하는 것이 좋습니다.

아래에서는 apply메소드를 이용해서, adam의 property인 age와 city를 변경해 주었습니다.

 

블록에 받는 객체의 멤버에 접근하는 경우 this는 생략이 가능합니다.

대신 this가 사라지면, 이것이 객체의 멤버인 외부 변수인지 구분하기 힘든 단점이 있습니다.

따라서 객체 멤버를 수정하는 일에 적합합니다.

 

위에서는 Student 클래스의 객체인 adam을 받았고, 그의 멤버변수 age에 접근하였습니다.

apply는 객체를 return해주므로, 받아서 print해 주었네요.

 

3-5. also

also는 context object가 it으로 return값은 object 자신입니다.

이것은 객체를 수정하거나 하지않고,

디버깅을 위한 로깅을 하는등의 부가적이거나 추가적인 일을 하려고 할 때 사용합니다.

 

 

4. 이용 목적별  구분

마지막으로 무조건 적인 것은 아니지만,

공식문서에서 추천하는 목적별 사용 구분을 알아보고 다시 정리해 보도록 하겠습니다.

 

- Non-null객체에 lambda를 사용하고자 할 경우 => let (람다 결과값 리턴)

- 객체를 변경하고자 할 경우 => apply (context object 리턴)

- 추가적인 효과 => also (context object 리턴)

- 객체를 변경하고 결과 값을 계산할 때 => run (람다 결과값 리턴)

-  Expression이 필요한 여러줄의 코드를 처리하고자 할 때 => run (람다 결과값 리턴)

- 객체에 함수호출들을 grouping할 때 => with (람다 결과값 리턴)

 

5. takeIf와 takeUnless

마지막으로 위에서 정리한 5가지 함수를 활용하는데 도움이 되는

takeIf와 takeUnless에 대해서 알아보도록 하겠습니다.

 

우선 takeIf와 takeUnless는 it이 contextObject이구요.

contextObject를 return해 줍니다.

메소드명에서 바로 알 수 있듯이 takeIf블록에 조건을 달아서 필터링 할 수 있는 것인데요.

 

그 조건을 달성한 경우 값을 받아서 사용할 수 있겠습니다.

takeUnless는 takeIf와는 반대로 동작하구요.(영어의 unless를 생각하시면 이해가 빠르겠습니다)

 

한가지 주의해야 할 점은 takeIf나 takeUnless는 조건을 만족하지 않을 경우,

null을 return한다는 점 입니다.

따라서, let을 safe call(?.)과 같이 사용해 주면 가장 좋겠지요.

 

 

6. 정리

5개나 되는 비슷한 함수들이 사용범위가 중첩되어 있으므로,

자주 사용해 보며 효율적인 convention등을 정리해서 사용하는 것이 좋을 것 같네요.

마지막으로 중요한 것은 이 5가지 함수들은 저희가 하고자 하는 과업을 위한 도구일 뿐이지,

함수를 위해서 과업을 하는 것은 아니므로, 어떻게 사용해야 한다는 정답은 없다는 것을 잊으면 않될 것 같습니다.

 

scope function과 관련된 내용은 이 글에서 업데이트 하도록 하겠습니다.

 

+ Recent posts