이 글은 Kotlin In Action을 참고 하였습니다.
더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다
이 글은 Kotlin In Action을 참고 하였습니다.
더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다
3.3 확장함수
package strings
fun String.lastChar(): Char = this.get(this.length-1)
특정 클래스에 확장 함수를 추가하려면 위 예제처럼 function을 만들때 앞에 해당 class를 붙여주면 됩니다.
- Receiver type: 확장이 정의될 클래스 ex) String
- Receiver object: 그 클래스의 인스턴스 객체 ex) this
이 함수를 사용할 때는 아래와 같이 사용하면 됩니다.
println("Kotlin".lastChar())
-> n
확장함수는 마치 기본 클래스에 추가적으로 함수를 넣는 기능을 합니다.
여기서 Receiver object인 this는 다른부분과 마찮가지로 생략 가능하므로 아래와 같이 줄여서 쓸수도 있습니다.
package strings
fun String.lastChar(): Char = get(length-1)
단! 확장함수는 receiver object의 private이나 protected함수에는 접근할 수 없습니다.
확장함수는 엄밀히 외부에서 해당 object에 접근하는것이므로 해당 class의 public 함수에만 접근이 가능합니다.
3.3.1 확장함수의 import
또한 String class만 import해서는 해당 함수를 사용할 수 없습니다.
아래처럼 명시적으로 import해야만 사용이 가능합니다.
import strings.lasChar
val c = "Kotlin".lastChar()
import strings.*
val c = "Kotlin".lastChar()
import strings.lasChar as last
val c = "Kotlin".last()
마지막 함수는 as를 이용하여 함수 이름을 변경했습니다.
만약 사용하는 class에서 import한 함수들이 확장함수와 같은 이름의 함수가 있을경우 last()라는 이름으로 치환하여 사용할때 유용한 기능입니다.
3.3.2 Java에서의 호출
// 자바
char c = StringUtilKt.lastChar("Kotlin");
3.3.3 확장 함수를 util로 정의
fun <T> Collection<T>.joinToString(
separator: String = ", ",
prefix: String = "",
postfix: String = ""): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
fun main(args: Array) {
val list = listOf(1, 2, 3)
println(list.joinToString(separator = "; ", prefix = "(", postfix = ")"))
val list = arrayListOf(1, 2, 3)
println(list.joinToString(" "))
}
joinToString 함수가 이제 collection의 확장함수가 되었으니, 관련 class들에서는 receiver object에서 직접 함수를 호출할 수 있습니다.
마치 collection에 포함되어 있던것처럼 말입니다.
만약 collection에서 더 specific하게 특정 type만 정의하고 싶다면 generic 대신 특정 형태를 넣어서 구현해도 됩니다.
fun Collection.join(
separator: String = ", ",
prefix: String = "",
postfix: String = "") = joinToString(separator, prefix, postfix)
fun main(args: Array) {
println(listOf("one", "two", "eight").join(" "))
}
3.3.4 확장함수의 override
open class View {
open fun click() = println("View clicked")
}
class Button: View() {
override fun click() = println("Button clicked")
}
fun main(args: Array) {
val view: View = Button()
view.click()
}
View class와 Button 클래스를 정의하고 click()이란 함수를 override했다고 하면,
위 코드의 결과는 "Button clicked"가 나옵니다.
자바와 동일하죠!
open class View {
open fun click() = println("View clicked")
}
class Button: View() {
override fun click() = println("Button clicked")
}
fun View.showOff() = println("I'm a view!")
fun Button.showOff() = println("I'm a button!")
fun main(args: Array) {
val view: View = Button()
view.showOff()
}
여기에 showOff()라는 확장함수를 View와 Button에 모두 추가했습니다.
이때 main 함수의 결과로는 "I'm a view!" 가 출력됩니다.
Button 객체가 View에 담겨있지만 확장함수는 view에 정의된게 호출된다는걸 명심해야 합니다.
추가적으로, 특정 클래스에 확장함수를 추가 할 때 이미 같은 이름의 멤버변수가 있다면 확장함수를 항상 무시됩니다.
즉 같은 이름이라면 멤버변수 > 확장함수의 우선순위를 가집니다.
3.3.5 Extension property
val String.lastChar: Char
get() = get(length - 1)
var StringBuilder.lastChar: Char
get() = get(length - 1)
set(value: Char) {
this.setCharAt(length - 1, value)
}
fun main(args: Array) {
println("Kotlin".lastChar)
val sb = StringBuilder("Kotlin")
sb.lastChar = '!'
println(sb)
}
확장된 property는 backing field를 가지고 있지 않습니다.
// 자바에서 호출시
StringUtilKt.getLastChar("Java");
3.4 컬렉션의 처리.
3.4.1 자바 Collection 확장 API
3.4.2 가변인자 (vararg)
fun listOf<T> (vararg values:T): List<T>{...}
또한 배영을 추가할때 자바와는 달리 spread 연산자인 *을 사용해서 원소를 풀어서 넣을 수 있습니다.
fun main(args: Array) {
val list = listOf("args: ", *args)
println(list)
}
위 코드는 list에 "args:"와 전달받은 array를 풀어서 넣습니다.
3.4.5 infix function과 destructuring
infix fun Any.to(other: Any) = Pair(this, other)
to 함수는 이렇게 정의되어 있습니다.
Any는 자바의 Object라고 생각하면 됩니다.
즉 어떤 object든 to를 쓸수 있으며, to를 쓰면 pair 객체를 반환해 줍니다.
받는 인자가 한개의 경우 infix function으로 만들 수 있습니다.
위 예제처럼 함수 앞에 infix를 붙이면 되며, infix가 붙이면 사용할 때 아래와 같이 표기할 수 있습니다.
1 to "one" // infix 함수에서 허용하는 형태
1.to("one") // 일반 함수처럼 사용하는 형태
to라는 infix function으로 생성된 pair는 destructuing을 지원합니다.
따라서 두개의 변수를 동시에 초기화하는게 가능합니다.
val (index, name) = 1 to "one"
일반적인 destructuring의 사용방법은 추후에 포스팅 하겠습니다. (한참 뒤에나 나옵니다.^^a)
fun <K,V> mapOf(vararg values:Pair<K,V>): Map<K,V>
mapOf는 위와같이 정의되어 있습니다.
따라서 destructuring을 통해서 아래와 같이 iteration이 가능했습니다.
for ((key, value) in sampleMap) {
...
}
for ((index, value) in collection.withIndex()) {
...
}
'개발이야기 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 class 생성자와 property (0) | 2018.04.20 |
---|---|
[Kotlin] 코틀린 삼중따옴표, 정규식, 문자열, 중첩함수 , 확장함수 (2) | 2018.04.18 |
[Kotlin] 코틀린의 Collection (2) | 2018.04.15 |
[Kotlin] 코틀린의 기초 #4 exception 처리 (0) | 2018.04.13 |
[Kotlin] 코틀린의 기초#3 iteration, for, while, in (2) | 2018.04.12 |