개발일지

Kotlin in A..Z (25) - 제네릭 본문

Kotlin (코틀린)

Kotlin in A..Z (25) - 제네릭

강태종 2020. 7. 19. 01:54

제네릭 개념

제네릭은 인스턴스를 생성할 때 자료형을 결정한다.

컴파일 시간에 자료형을 검사하여 코드의 안정성을 높인다.

제네릭의 본질은 런타임에 ClassCastException을 막아주어 안정성을 높이는데 있다.


제네릭 사용법

자료형을 결정할 수 없는 경우를 조심해야한다.

엥글 브래킷(<>) 사이에 형식 매개변수를 넣어 선언한다.

 

코드

// 제네릭 클래스
class Box<T>(vararg val elements: T) {
    fun printElements() {
        for(i in elements) {
            print("$i ")
        }

        println()
    }
}

// 제네릭 함수
fun<T> printGeneric(element: T) {
    println(element)
}

fun main() {
    // 자료형을 유추할 수 있으면 앵글 브래킷을 생략할 수 있다.
    val box1 = Box(1)
    box1.printElements()

    val box2: Box<String> = Box<String>("Hi", "Hello")
    box2.printElements()

    printGeneric(123)
    printGeneric("123")
}

 

결과

1 
Hi Hello 
123
123

보편적인 형식 매개변수 이름

규칙은 아니지만 보편적으로 사용하는 방식이다.

이름 의미
E Element
K Key
N Number
T Type
V Value

람다식에 제네릭 사용하기

 

코드

fun <T> calculate(x: T, y: T, op: (T, T) -> T): T {
    return op(x, y)
}

fun main() {
    val result1 = calculate(1, 2) { x, y -> x + y }
    println(result1)
    
    val result2 = calculate("ABC", "DEF") { x, y -> x + y }
    println(result2)
}

 

결과

3
ABCDEF

자료형 제한하기

 

코드

// Number형식의 자료형만 제한한다.
fun <T: Number> numberCalculate(x: T, y: T, op: (T, T) -> T): T {
    return op(x, y)
}

fun main() {
    val result1 = numberCalculate(1, 2) { x, y -> x + y }

    // String은 Number형이 아니기 때문에 Error
    // is not satisfied: inferred type String is not a subtype of Number
    val result2 = numberCalculate("ABC", "DEF") { x, y -> x + y }
}

다수 조건의 형식 매개변수 제한하기

 

코드

interface A
interface B

class TotalHandler : A, B
class SmallHandler : A

// T는 A와 B를 만족하는 자료형이여야 한다.
class MyClass<T> where T: A, T: B

fun main() {
    val myClass1 = MyClass<TotalHandler>()

    // SmallHandler는 A만 가지고 B를 갖고있지 않기 때문에 Error
    // Kotlin: Type argument is not within its bounds: should be subtype of 'B'
    val myClass2 = MyClass<SmallHandler>()
}
Comments