Android Development with Kotlin - Extension Functions and Properties |
이 정리글은 Kotlin in Action 책을 보고 실무에 Kotlin 을 사용하던 사람이 몰랐던 내용이나 remind 하고 싶은 내용을 위주로 정리한 글입니다.
제대로 내용을 파악하시려면 책을 구매해서 읽어보세욤~
-
extension function 들도 inline 가능하다.
-
extension function 과 같은 이름의 member function 이 있다면,
항상 member function 이 우선순위를 갖는다.
여기서 member function 이라 하면 super class 에 있는 member function 들도 해당한다.
이 말은 extension function 은 기본 동작을 변경할 수는 없고, 기능 추가의 개념으로만 쓰인다는 것.
-
아래 케이스를 통해 동일 이름의 extension function 이 있을 경우 define 된 type 의 것이 불린다는 규칙을 알 수 있다.
그래서 lib 을 설계하거나 할 때, subclass 에 동일 이름의 extension function 을 사용하지 않도록 주의해야 한다. 의도치 않은 shadow 효과를 낼 수 있다.
abstract class A class B: A() fun A.foo() { println("foo(A)") } fun B.foo() { println("foo(B)") } val b = B() b.foo() // prints: foo(B) (b as A).foo() // 1, prints: foo(A) val a: A = b a.foo() // 1, prints: foo(A)
-
companion object 에도 extension 을 추가할 수 있다.
fun A.Companion.foo() { … } // A 에 empty 더라도 companion object 가 있어야 한다.
이렇게 추가된 extension 은 static 함수처럼 사용 가능하다.
A.foo() // instance 에 부르는 것이 아니다.
-
operator overloading 도 가능하다.
-
extension 은 순기능도 있지만, 새로운 developer 가 왔을 때 새롭게 API 를 배워야 하는 단점도 있다.
-
extension property 는 backing field 가 없는 case 에만 설정될 수 있다.
read-only 면 getter 만 생성되고, 그렇지 않으면 getter, setter 가 extension 으로 생성된다고 보면 된다.
-
언제 extension function 을 써야 할지 언제 extension property 를 써야할지 고민이라면. 아래를 보라.
다음 조건을 충족하는 경우에만 property 로 쓰는 것이 좋다.
error 를 던지지 않음.
O(1) complexity 를 가짐
계산이 오래 걸리지 않음.
여러번 호출해도 항상 같은 결과를 return
-
member extension function & property 도 가능하다.
이들은 top level 에 정의된 녀석들이 아니라 class 안에 정의된 녀석들이다.
이들은 기본적으로 해당 class 와 children 에서만 접근할 수 있다.
top-level 에 private access level 로 정의한 것도 비슷하지만.
top-level private 은 해당 파일에 종속적인 visibility 이다.
또한 member extension 은 function 과 비슷하게 member 변수들에도 접근 가능하다.
그렇다면 member extension 이 일반 function 에 대해 장점이 무엇이 있을까?
extension 하는 receiver context 를 물고 가서 코드를 짧게 가져갈 수 있다.
-
member extension function 의 경우 extension receiver 뿐만 아니라, dispatch receiver 에 대한 암시적 참조를 가지고 있다.
동일한 function signature 를 가진 경우 extension receiver 가 항상 우선권을 갖고 호출이 된다.
dispatch receiver 는 this@MainActivity 와 같이 명시적으로 호출해주어야 한다. ( 유일한 경우는 필요 없다. )
-
forEach 의 경우 iterate 하고 끝나는데..(return 이 Unit) onEach 는 extension receiver 를 그대로 return 한다
onEach 는 보통 logging 용으로 잘 사용하고 Kotlin 1.1 부터 사용 가능하다.
-
collection 을 index 와 함께 처리하려면 아래 api 들을 잘 사용하면 된다.
Collection.withIndex() Collection.filterIndexed{ i, v -> … } Collection.mapIndexed{ i, v ->… } Collection.forEachIndexed{ i, v -> … }
-
class User(val points: Int) val users = listOf(User(10), User(1_000), User(10_000)) val points = users.map { it.points }. sum()
요 녀석은 쓸 데 없이 list 를 한번 더 생성하기 때문에.. sumBy 를 쓰면 좋다.
val points = users.sumBy{ it.points }
값 치환을 하려면 sumByDouble 등과 같은 API 를 쓰면 된다.
-
count 는 predicate 를 만족하는 갯수를 return 하는데, predicate 를 명시하지 않으면 그냥 collection 의 size 가 나온다.
-
sorted() 는 sorted list 를 return 한다. 기본 오름차순이다.
내림차순으로 하려면 sortedByDescending{ 기준 } 을 호출해주면 된다.
-
take() 함수를 통해 앞선 몇개만 추출해낼 수 있다.
-
comparator 가 있다면 sortedWith( comparator ) 를 통해 sorting 할 수도 있다.
그리고 comparator 를 만들지 않아도 되도록 compareBy 와 compareByDescending 이라는 함수들도 제공한다. 저 함수들이 comparator 를 만들어준다
-
groupBy function 을 이용해 쉽게 map 을 만들 수도 있다.
val grouped = listOf("ala", "alan", "mulan", "malan") .groupBy { it.first() } println(grouped) // Prints: {'a': ["ala", "alan"], "m": ["mulan", "malan”]}
-
streaming 에 사용하는 sequence 를 collection 을 통해서가 아닌 직접 생성할 수도 있다.
generateSequence(1) { it + 1 } // 1부터 1을 stepping 해서 sequence 를 만들어냄
-
function type with receiver ( lambda with receiver ) 는 일반 extension function 과 동일하지만, receiver 를 this 로 받을 수 있다는 차이점이 있다.
var power: Int.(Int) -> Int
-
let 은 보통 ?. operator 와 함께 사용되며, let 안에 it 으로 receiver 가 전달되고. return 값이 return 된다.
also 는 it 으로 receiver 가 전달되고, receiver 가 그대로 return 된다.
apply 는 it 대신 receiver 가 context 로 전달이 되고, receiver 가 그대로 return 된다
with 는 it 대신 receiver 가 context 로 전달되고, return 값이 return 된다. ( extension 이 아님 )
run 은 it 대신 receiver 가 context 로 전달되고, return 값이 return 된다. ( extension 임 )
-
DSL 을 사용하면 addTextWatcher 를 멋지게 구현할 수 있다.
class TextWatcherConfig : TextWatcher { private var beforeTextChangedCallback: (BeforeTextChangedFunction)? = null // 1 private var onTextChangedCallback: (OnTextChangedFunction)? = null // 1 private var afterTextChangedCallback: (AfterTextChangedFunction)? = null // 1 fun beforeTextChanged(callback: BeforeTextChangedFunction){ // 2 beforeTextChangedCallback = callback } fun onTextChanged(callback: OnTextChangedFunction) { // 2 onTextChangedCallback = callback } fun afterTextChanged(callback: AfterTextChangedFunction) { // 2 afterTextChangedCallback = callback } override fun beforeTextChanged (s: CharSequence?, start: Int, count: Int, after: Int) { // 3 beforeTextChangedCallback?.invoke(s?.toString(), start, count, after) // 4 } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { // 3 onTextChangedCallback?.invoke(s?.toString(), start, before, count) // 4 } override fun afterTextChanged(s: Editable?) { // 3 afterTextChangedCallback?.invoke(s) } } private typealias BeforeTextChangedFunction = (text: String?, start: Int, count: Int, after: Int)->Unit private typealias OnTextChangedFunction = (text: String?, start: Int, before: Int, count: Int)->Unit private typealias AfterTextChangedFunction = (s: Editable?)->Unit fun TextView.addOnTextChangedListener(config: TextWatcherConfig.()->Unit) { val textWatcher = TextWatcherConfig() textWatcher.config() addTextChangedListener(textWatcher) }
위의 코드들이 있다면.. 아래와 같이 쓸 수 있다.
searchView.addOnTextChangedListener { onTextChanged { text, _, _, _ -> presenter.onSearchChanged(text) } }
훨씬 간결하게 쓸 수 있고, 사용하지 않는 param 도 감출 수 있고, default function impl 도 주입할 수 있고, 사용하지 않는 function 들의 empty override 도 줄일 수 있다.
'프로그래밍 놀이터 > Kotlin, Coroutine' 카테고리의 다른 글
[android] AsyncTask 를 Coroutine 으로 바꿔본 후기 (0) | 2019.02.07 |
---|---|
[도서 정리] Android Development with Kotlin - Delegates (0) | 2018.12.17 |
[도서 정리] Android Development with Kotlin - Generics Are Your Friends (0) | 2018.12.15 |
[도서 정리] Android Development with Kotlin - Functions as First-Class Citizens (0) | 2018.12.14 |
[도서 정리] Android Development with Kotlin - Classes and Objects (0) | 2018.12.13 |
댓글