Scala는 Java 5(즉, JDK 1.5)와 같이 파라미터화된 클래스의 빌트인 자원
을 제공한다. 즉, 클래스 내부에서 사용할 데이터 타입을 외부에서 지정할 수 있도록 하는 제네릭 클래스
를 사용하면 유용하게 개발이 가능하다. 특히, 컬렉션 클래스의 개발에 유용하다.
제네릭을 사용하면 외부에서 자료형을 지정해줄 뿐만 아니라, 지정된 자료형이 아닌 잘못된 타입이 들어왔을 시 컴파일러가 이를 탐지할 수 있어 안정적이다.
예를 들어 큐(Queue)
를 직접 만든다고 생각해보자. 이때 큐의 내부 자료형은 모든 타입이 될 수 있다. 즉, 문자열 큐가 될 수도 있고, Int형 큐가 될 수도 있는 것이다. 이런 경우 어떤 식으로 코드를 작성할까?
class Queue[T] {
var elems: List[T] = Nil
def push(x: T): Unit =
elems = elems :+ x
def front: T = elems.head
def pop(): Unit = { elems = elems drop 1 }
}
위와 같이 임의의 타입
을 지정하는 T
라는 항목의 타입으로 변수형을 지정하였다. 즉, 해당 큐를 사용할 때 필요한 타입을 넣을 수 있도록 한 것이다.
임의의 타입
제네릭에서 임의의 타입을 지정할 때 위와 같은 키워드들로 설정한다.
물론, < E > 대신 < Ele >와 같은 형태로 사용해도 되지만 위의 표에 나와있는 타입들이 통상적으로 사용하는 타입이므로 위와 같이 원하는 description에 맞는 한 글자 키워드를 사용하는 것이 좋다.
위의 큐가 실제로 잘 동작하는지 확인해보자.
Queue
클래스를 보면 임의의 타입인 T
를 넣어놓았다. 그리고 현재 만들고 싶은 큐는 Int형이므로 new
키워드로 새로운 큐를 만들 때 중괄호 안에 원하는 타입을 넣어주면 된다.
그 후, 모든 작업들이 제대로 동작하는 것이 보인다. 이때 주의해야할 점은 타입 파라미터는 올바른 항목(타입 T
, 예제에서는 Int)만을 사용하도록 강제한다는 점이다.
위의 예시에서는 queue를 Int
타입으로 선언하여 내부에 Int의 값만 들어오도록 강제하는데, 만약 다른 큐에서 다른 데이터 타입(Double이나 Boolean 혹은 객체)이 들어오도록 선언하였다면 그 역시 제대로 동작할 것이다.
위의 코드는 String
형으로 만든 다른 큐이다. 위의 코드 역시 내부 자료형은 달라졌지만 의도한 바를 잘 수행하는 것을 알 수 있다. 이처럼 클래스 내부의 임의의 자료형이 들어오는 것을 허용하는 것이 제네릭이다.
또한, 제네릭 클래스의 서브 타입은 "불가변"이다. 이는 상당히 큰 제약이므로 스칼라는 제네릭 타입의 서브타입을 지정하는 행위를 제어하기 위해 타입 파라미터 어노테이션 방법을 제공한다.