제네릭과 배열 (1/3)

장똑대·2022년 4월 14일
0

Do it! 코틀린 프로그래밍 [셋째마당, 코틀린 표준 라이브러리의 활용] 학습

✏️1. 제네릭 다루기✏️

  • 제네릭(Generic) 은 클래스 내부에서 사용할 자료형을 나중에 인스턴스를 생성할 때 확정
  • 자료형의 객체들을 다루는 메서드나 클래스에서 컴파일 시간에 자료형을 검사해 적당한 자료형을 선택할 수 있도록 하기 위함
  • 객체의 자료형을 컴파일할 때 체크하므로 객체 자료형의 안정성을 높이고 형 변환의 번거로움이 줄어듬

📌 제네릭의 일반적인 사용 방법

  • 앵클 브래킷(<>) 사이에 형식 매개변수를 넣어 선언
  • 형식 매개변수는 하나 이상 지정 가능
  • 형식 매개변수는 자료형을 대표하는 용어로 T와 같이 특정 영문의 대문자로 사용하며 나중에 필요한 자료형으로 대체
  • 다양한 자료형을 다뤄야 하는 컬렉션에 많이 사용
  • 의도하지 않은 자료형의 객체를 지정하는것을 막을 수 있음
  • 객체를 사용할 때 원래의 자료형에서 다른 자료형으로 형 변환 시 발생할 수 있는 오류를 줄여줌

⬇️ 제네릭 사용 예시

class Box<T>(t: T) { // 형식 매개변수 T
    var name = t
}

fun main() {
    val box1: Box<Int> = Box<Int>(1)
    val box2: Box<String> = Box<String>("Hello")
    
    // (1) 자료형 생략 가능
    val box1 = Box(1)
    val box2 = Box("Hello")
    
    println(box1.name)
    println(box2.name)
}

-> (1) 객체 생성 시 만일 생성자에서 유추될 수 있는 자료형이 있다면 선언된 자료형인 <String> 이나 <Int>는 생략 가능
-> 형식 매개변수 T를 이용해 인자의 자료형을 고정할 수 없거나 예측할 수 없을 는 경우 실행 시간에 자료형을 결정할 수 있게 됨

📌 제네릭에서 사용하는 형식 매개변수 이름

형식 배개변수 이름의미
E요소(Element)
K키(Key)
N숫자(Number)
T형식(Type)
V값(Value)
S,U,V etc.두 번째, 세 번째, 네 번째 형식

1-1. 제네릭 클래스

  • 형식 매개변수를 1개 이상 받는 클래스
  • 클래스를 선언할 때 자료형을 특정하지 않고 인스턴스를 생성하는 시점에서 클래스의 자료형을 정함
class MyClass<T> { // 1개의 형식 매개변수를 가지는 클래스

	// (1) !오류! 형식 매개변수는 프로퍼티에 사용하는 경우 클래스 내부에서 사용 불가
    var myProp: T 
    
    fun myMethod(a: T) { } // 메서드의 매개변수 자료형에 사용
}

-> (1) 자료형이 특정되지 못하므로 인스터스 생성 불가.

⬇️주 생성자, 부 생성자에 형식 매개변수 지정하기

class MyClass<T>(val myProp: T) {} // 주 생성자의 프로퍼티

class MyClass<T> {
    val myProp: T // 프로퍼티
    constructor(myProp: T) { // 부 생성자 이용
        this.myProp = myProp
    }
}

fun main() {
    // 주 생성자 myProp에는 12가 할당되며 Int형으로 결정
    var a = MyClass<Int>(12) 
}

-> 객체 a가 생성되면서 자료형이 Int형으로 결정되며 생서자에 의해 12가 myProp에 초기화

📌 형식 매개변수의 null 제어

  • 제네릭의 형식 매개변수는 기본적으로 null 가능한 형태로 선언

⬇️ 형식 매개변수 null 제한하기

class GenericNull<T: Any> { }

fun main() {
    val obj = GenericNull<Int?>() // !오류! null 허용 X
}

-> 형식 매개변수는 null이 아닌 Any로 제한하여 null을 지정할 수 없게 함


1-2. 제네릭 함수/메서드

  • 형식 매개변수를 받는 함수나 메서드
  • <K, V> 와 같이 형식 매개변수를 여러 개 사용할 수 있음
  • 자료형의 결정은 함수가 호출될 때 컴파일러가 자료형을 추론
  • 반환 자료형과 매개변수 자료형에 사용가능
  • fun <형식 매개변수[,...]> 함수 이름(매개변수: <매개변수 자료형>[,...]: <반환 자료형>
fun <T> genericFunc(arg: T): T? {...} // 배개변수와 반환 자료형에 형식 매개변수 사용
fun <K, V> put(key: K, value: V): Unit {...} // 형식 매개변수가 2개

📌 제네릭과 람다식

fun <T> add(a: T, b: T) {
	return a + b // !오류! 자료형을 아직 결정할 수 없음
}
  • 람다식을 매개변수로 받으면 자료형을 결정하지 않아도 실행 시 람다식 본문을 넘겨줄 때 결정되므로 이러한 문제를 해결 할 수 있음

⬇️ 람다식에서 제네릭 사용

fun <T> add(a: T, b: T, op: (T, T) -> T): T {
    return op(a, b)
}

fun main() {
    val result = add(2, 3) { a, b -> a + b }
    println(result)
}

⬇️ 코드의 가독성을 높이기 위해 람다식만 변수로 정의하기

// 변수 선언부가 있는 경우 표현식의 자료형 생략
var sumInt: (Int, Int) -> Int = {a, b -> a + b}
// 변수 선언부가 생략된 경우에는 표현식에 자료형 표기
var sumInt2: {a:Int, b:Int -> a + b}
...
println(add(2, 3, sumInt))
println(add(2, 3, sumInt2))
profile
장똑대와 안드로이드

0개의 댓글

관련 채용 정보