이 글은 Kotlin In Action을 참고 하였습니다.
더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다
9.1 Generic type parameter
코틀린도 자바와 같이 Generic을 지원합니다.
일상적으로 사용하기에는 자바와 다르지 않으나, 코틀린 좀더 많은 Generic 기능을 지원합니다.
자바는 1.5부터 제네릭 개념이 들어가면서 하위 호환성을 위해 타입을 정의하지 않고도 사용할 수 있으나, 코틀린은 반드시 타입을 정의하고 써야 합니다.
예를 틀면 자바는 List로 타입 선언이 가능하지만, 코틀린은 List<String> 처럼 반드시 타입을 넣어야 합니다.
9.1.1 제네릭 함수와 Property
fun <T> List<T>.slice(indices: IntRange): List<T>
제너릭 함수는 위와 같이 정의합니다.
아직은 자바와 별다를게 없습니다.
호출할때 type 인자를 명시적으로 넣어도 되지만 넣지 않더라도 컴파일러가 알아서 타입을 추론합니다.
fun main(args: Array) {
val letters = ('a'..'z').toList()
println(letters.slice<char>(0..2))
println(letters.slice(10..13))
}
Extension property만 제너릭 하게 만들 수 있습니다.
일반 property에 generic을 사용하면 컴파일 오류가 납니다.
9.1.2 제네릭 클래스
9.1.3 Type parameter limitation
// 자바
<T extends Number> T sum(List<T> list)
//코틀린
fun <T: Number> List<T>.sum():T
코틀린에서 타입 상한을 설정하면 당연한 예기지만 상한 타입으로 취급할 수 있습니다.
fun oneHalf(value: T): Double {
return value.toDouble() / 2.0 // toDouble()는 Number의 함수다.
}
fun main(args: Array) {
println(oneHalf(3))
}
fun <T: Comparable<T>> max(first: T, second: T): T {
return if (first > second) first else second
}
fun main(args: Array) {
println(max("kotlin", "java"))
}
위 예제에서 T는 Comparable<T>를 상한으로 갖습니다.
즉. max()를 사용할때의 인자는 Comparable을 구현하고 있어야 한다는 의미가 됩니다.
String은 Comparable을 구현하고 있으므로 해당 코드는 정상적으로 동작합니다.
물론 int와 String을 넣으면 컴파일 에러가 나겠죠?
여담이지만 first > second 에서 > 연산자는 코틀린 convention에 따라 first.compareTo(second)로 변경됩니다.
(기억이 안난다면 http://tourspace.tistory.com/118?category=797357 를 다시한번 읽어보셔도 됩니다.
import java.time.Period
fun <T> ensureTrailingPeriod(seq: T)
where T : CharSequence, T : Appendable {
if (!seq.endsWith('.')) {
seq.append('.')
}
}
fun main(args: Array<String>) {
val helloWorld = StringBuilder("Hello World")
ensureTrailingPeriod(helloWorld)
println(helloWorld)
}
아주 드물지만 두개의 제약을 걸어야 하는 경우 where 연산자를 씁니다.이때의 함수타입은 나열된 타입들을 전부 만족해야 합니다.
9.1.4 Non-Null Type parameter 설정
class Friend <T> {
fun getUniqueId(value: T) {
value?.hashCode() //null 처리가 필요하다
}
}
fun main(string: Array) {
val friend = Friend()
friend.getUniqueId(null) //가능
}
따라서 NonNull인 타입으로 제한하려면 명시적으로 <T : Any> 로 선언해야 합니다.
<T> 만 선언한다면 <T: Any?>와 같습니다.
9.2 Generic의 run time 동작
9.2.1 제네릭의 run time
fun printSum(c: Collection<*>) {
val intList = c as? List // 여기서 warning 발생
?: throw IllegalArgumentException("List is expected")
println(intList.sum())
}
fun main(args: Array) {
printSum(listOf(1, 2, 3))
val list = listOf(1,2,3)
if (list is List<Int>) {
println("ok")
}
}
만약 인자가 두개 이상이라면 인자 개수만큼 *을 표시해야 합니다
9.2.2 reified로 타입 실체화
inline fun <reified T> isA(value: Any) = value is T //컴파일 가능!!
fun main(args: Array) {
println(isA<String>("abc"))
println(isA<Int>(123))
}
list 함수중에 filterIsInstance를 사용하면 특정 타입의 원소만 분리해 낼 수 있습니다.
fun main(args: Array) {
val items = listOf("one", 2, "three")
println(items.filterIsInstance<String>())
}
이 함수는 내부적으로 for문을 돌면서 if (element is T)를 체크합니다.
단 자바에서는 reified가 붙은 함수는 호출할 수 없습니다.
또한 inline 함수는 람다가 들어간 경우에만 최적화 될수 있다고 얘기했지만, 이 경우 타입 실제화를 위해서 inline을 함수를 써야만 합니다.
만약 함수 내용이 길다면, 실제화가 필요없는 부분은 따로 함수로 뽑아내는게 효율적입니다.
9.2.3 실체화한 타입으로 클래스 참조
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
이는 MainActivity::class.java는 MainActivity.class의 코틀린 표현입니다.
하지만 reified를 이용하면 다르게 표현할 수 있습니다.
inline fun <reified T : Activity> Context.startActivity() {
val intent = Intent(this, T::class.java)
startActivity(intent)
}
startActivity<MainActivity>()
9.2.4 Reified type parameter limitation
- 사용가능 case
- type 검사와 캐스팅 (is, !is, as, as?)
- 추후 언급되는 코틀린 리플렉션API(::class)
- 코틀린타입에 대응하는 java.lang.Class 얻기 (::class.java)
- 다른 함수를 호출할 대 타입 인자로 사용
- 사용 불가 case
- Type 파라미터 클래스의 인스턴스 생성
- Type 파라미터의 companion object method 호출
- reified 되지 않는 type을 받아 reified type을 받는 함수에 넘기기
- 클래스, property, inline 함수가 아닌 함수의 타입 파라미터를 reified로 지정하기
'개발이야기 > Kotlin' 카테고리의 다른 글
[Kotlin] 코틀린 - 코루틴#1 기본! (3) | 2018.12.03 |
---|---|
[Kotlin] 코틀린 constructor vs init block (2) | 2018.05.29 |
[Kotlin] 코틀린 High order function (0) | 2018.05.09 |
[Kotlin] 코틀린 연산자 오버로딩 #2 컬렉션, in, rangeTo, iterator, destructuring, Property delegation, by (0) | 2018.05.06 |
[Kotlin] 코틀린 연산자 오버로딩 #1 - 산술연산자, 비트연산자, equals, compareTo (3) | 2018.05.03 |