코틀린의 표준 라이브러리의 표준 함수들을 살펴보고 안드로이드에서의 예시들을 살펴봅시다! 이들을 활용하면 코드를 훨씬 간결하게 만들 수 있답니다!
let, apply, with, also, run 의 가장 큰 차이는 람다식의 접근 방법과 반환 방법입니다.
public line fun <T, R> T.let(block: (T) -> R) : R { ... return block(this) }
val firstName : String?
val lastName : String
if(firstName != null) print("$firstName $lastName")
else print("$lastName")
//let 사용
firstName?.let { print("$firstName $lastName") } ?: print("$lastName")
val feedDetailRetrofitInterface = ApplicationClass.retrofit.create(FeedDetailRetrofitInterface::class.java)
feedDetailRetrofitInterface.postLike(LikeRequest(contentsNo))?.let {
if (it.isSuccessful) it.body()?.let { res ->
if (res.isSuccess) view.onSuccessPostLike(itemPosition)
else view.onFailPostLike()
} else view.onFailPostLike()
}
저는 retrofit 통신에서 특히 간결하게 let 으로 위와 처리합니다ㅎㅎ
public inline fun <T> T.also(block : (T) -> Unit) : T { block(this); return this }
public line fun <T, R> T.let(block: (T) -> R) : R { ... return block(this) }
also 함수는 let 과 유사해보이지만, 반환값이 다릅니다. also 함수는 블록 안의 코드 수행 결과와 상관없이 T인 객체 this를 반환합니다.
fun main() {
data class Person(var name : String, var skills : String)
var person = Person("Kildong", "Kotlin")
val a = person.let {
it.skills = "Android"
"success" //마지막 문장을 결과로 반환
}
println(person)
println("a : $a")
val b = person.also {
it.sills = "Java"
"success" //마지막 문장은 사용되지 않음
}
println(person)
println("b : $b")
}
//Person(name=Kildong, skills=Android)
//a: success
//Person(name=Kildong, skills=Java)
//b: Person(name=Kildong, slills=Java)
답이 여러분 예상과 같았나요?
also 는 람다식 본문을 처리하긴 하지만, 마지막 표현식이 b에 할당되는 것이 아니라, person 객체가 할당됩니다.
noTaskAddView = (findViewById<TextView>(R.id.noTasksAdd)).also {
it.setOnClickListener { showAddTask() }
}
안드로이드에서는 뷰 객체를 초기화 할 때, setOnClickListener 도 함께 초기화해서 변수에 할당하고 싶을 때, also 는 반환값이 객체 T 자체이기 때문에 이렇게 사용하면 되겠죠?ㅎㅎ
public inline fun <T> T.also(block : (T) -> Unit) : T { block(this); return this }
public line fun <T, R> T.let(block: (T) -> R) : R { ... return block(this) }
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
그 중 apply() 함수와 also() 함수는 둘 다 객체 T를 block 으로 전달하고 객체 자체인 this 를 반환합니다. 하지만 apply() 는 T.()와 같은 표현에서 람다식이 확장 함수로 처리된다는 점이 다릅니다.
fun main() {
data class Person(var name: String, var skills: String)
var person = Person("Ejjjang", "Kotlin")
person.also { it.skills = "Java" }
person.apply { skills = "Swift" }
}
apply() 가 also() 함수와 다른 점은 객체를 넘겨 받는 방식입니다.
also() 함수는 it 을 통해 멤버에 접근합니다. 하지만 apply() 에서는 함수 타입에 리시버가 있기 때문에 this 를 생략하고 멤버 이름만 사용하고 있습니다.
apply() 함수는 위의 예시처럼 특정 객체를 생성하면서 함께 호출해야 하는 초기화 코드가 있는 경우 많이 사용됩니다.
val markerOptions = MarkerOptions().apply {
position(positionLatLng)
title(searchResult.buildingName)
snippet(searchResult.fullAddress)
}
위에서 말한 것 처럼 객체를 생성하면서 여러 번 멤버에 접근해야 할 때 유용하게 쓰입니다.
public inline fun <R> run(block: () -> R):R = return block()
public inline fun <T, R> T.run(block: T.() -> R):R = return block()
run() 함수는 인자가 없는 익명 함수처럼 동작하는 형태와 객체에서 호출하는 형태, 2가지로 사용할 수 있습니다.
val returnObj = person.run {
this.name = "Dooly"
this.skills = "C++"
"SUCCESS"
}
여기서 returnObj 에는 마지막 표현식인 "SUCCESS" 가 할당이 됩니다. 마지막 표현식이 없으면 Unit 이 반환됩니다.
public inline fun <T, R> with(receiver: T, block: T.() -> R):R = receiver.block()
with() 함수는 run() 함수와 거의 동일한데, 인자로 받는 객체를 이어지는 block 의 receiver(T.) 로 전달하며 결괏값을 반환합니다.
supportActionBar?.let {
with(it) {
setDisplyHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_clear_white)
}
여기서 재미있는 것은 let() 함수와 with() 함수를 병합하면 run() 함수로 다음과 같이 표현할 수 있다는 것입니다.
supportActionBar?.run {
setDisplyHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_clear_white)
}
private fun bindViews() = with(binding) {
fabMyLocation.setOnClickListener {
getMyLocation()
}
}
binding을 초기화 해준 경우 binding.fabMyLocation 해줄 필요없이 바로 fabMyLocation 에 접근할 수 있겠죠. 여러 view 를 건드려야 할 때 유용합니다.
안드로이드 개발을 하다보면 자신만의 표준함수 쓰는 곳?! 이 생기는 것 같더라구요 ㅋㅋ 다른 사람들이 좋은 곳에 사용하는 것을 보면 저도 따라서 써보고 했는데 제 코드가 더욱 간결해지고 깔끔해져서 표준 함수를 더 열심히 쓰고 싶은ㅋㅋ 마음이 들더라구요!
그러나!! 책에도 나와있었지만 너무 남용하는 것은 오히려 가독성을 떨어뜨릴 수 있으니 조심해야겠지용?! ㅎㅎ
아직 run 을 제대로 활용해본 적이 없는데 앞으로 좋은 활용처를 찾으면 example 부분에 추가할 수 있도록 하겠습니다!ㅎㅎ
도서 <Do it! 코틀린 프로그래밍> http://www.yes24.com/Product/Goods/74035266?OzSrank=1