-
Scala도 다른 JVM언어와 마찬가지로 런타임에 타입을 소거
- 컴파일시에는 가능한 타입 정보에 대한 접근이 런타임에는 불가능
-
Scala.reflect.Manifest
,TypeTags
: 컴파일타임에 접근 가능한 타입 정보를 런타임에 전달TypeTag[T]
는 컴파일 타임의 타입T
의 런타임 타입 표현을 캡슐화.TypeTag
는, 2.10 이하 버전에서 사용되었던, 더 많은 기능을 내포한Manifest
의 대안이며, Scala reflection에 통합됨
-
scala.reflect.api.TypeTags#TypeTag
- 스칼라 타입의 완전한 타입 서술자
- e.g.
TypeTag[List[String]]
은scala.List[String]
의 모든 타입 정보를 담고 있다
-
scala.reflect.ClassTag
- 스칼라 타입의 부분적인 타입 서술자
- e.g.
ClassTag[List[String]]
은 소거되는 타입의 타입 정보만 담는다.- 여기서는
scala.collection.immutable.List
- 여기서는
ClassTag
는 타입의 런타임 클래스에만 접근을 허용scala.reflect.ClassManifest
와 유사함
-
scala.reflect.api.TypeTags#WeakTypeTag
- 추상 타입을 위한 타입 서술자
Manifest
와 마찬가지로,TypeTag
도 컴파일러에 의해 생성되며 세 가지 방법으로 얻을 수 있다
Universe
를 통해 사용가능한typeTag
메서드를 사용하면, 특정 타입에 대한TypeTag
를 직접 획득 가능
import scala.reflect.runtime.universe._
val tt = typeTag[Int]
import scala.reflect._
val ct = classTag[String]
- 위 두 메서드(
typeTag
,classTag
)는 각각 주어진 타입 아규먼트T
에 대하여TypeTag[T]
와ClassTag[T]
를 생성한다
- 컴파일러가
TypeTag
를 생성하도록 요청할 수 있음- 이는
TypeTag[T]
타입에 implicit 을 표기하는 것으로 수행 가능- 컴파일러가 일치하는 타입의 implicit value를 찾지 못한다면
TypeTag[T]
를 자동으로 생성한다
- 컴파일러가 일치하는 타입의 implicit value를 찾지 못한다면
Note
: 일반적으로 메서드나 클래스에만 implicit parameter를 사용하여 수행
- 이는
- 임의의 object를 받아서 그 obj의 정보를 출혁하는 메서드를
TypeTag
를 사용하여 작성하는 예제.
import scala.reflect.runtime.universe._
def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
val targs = tag.tpe match {
case TypeRef(_, _, args) => args
}
println(s"type of $x has type arguments $targs")
}
T
라는 타입 매개변수를 받는 제네릭 메서드paramInfo
- implicit parameter인
(implicit tag: typeTag[T])
적용 - 그 후,
TypeTag
의tpe
메서드를 사용하여tag
가 나타내는 타입에 직접 접근 가능
- 좀 덜 복잡한 방법
def myMethod[T: TypeTag] = ???
import scala.reflect.runtime.universe._
def paramInfo[T: TypeTag](x: T): Unit = {
val targs = tag.tpe match {
case TypeRef(_, _, args) => args
}
println(s"type of $x has type arguments $targs")
}
- 주어진 context bound
[T: TypeTag]
를 통해 - 컴파일러는
TypeTag[T]
에 대한 implicit parameter를 생성 후 - 윗 단락의 implicit parameter를 넘기는것과 같이 메서드를 수정
WeakTypeTag[T]
는TypeTag[T]
를 보편화한 것- 일반적인
TypeTag
과 달리, 타입 표현을 위한 구성요소는, 타입 매개변수 혹은 추상 타입에 대한 참조일 수 있음 - 하지만,
WeakTypeTag[T]
는 가능한 한 강건해지려고 노력함i.e.
참조된 타입 매개변수나 추상 타입에 대해 type tag가 사용 가능할 때,WeakTypeTag[T]
에 구체적인 유형을 포함시킨다
def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = {
val targs = tag.tpe match {
case TypeRef(_, _, args) => args
}
println(s"type of $x has type arguments $targs")
}
scala> def foo[T] = weakParamInfo(List[T]())
foo: [T]=> Unit
scala> foo[Int]
type of List() has type arguments List(T)
TypeTag
는 2.10 이하의scala.reflect.Manifest
개념에 느슨하게 부합한다scala.reflect.ClassTag
는scala.reflect.ClassManifest
에 해당scala.reflect.api.TypeTags#TypeTag
는scala.reflect.Manifest
에 대부분 일치- 기타 2.10 이전 버전의
Manifest
타입은 2.10의Tag
에 직접적으로 구현된 구현체는 없음
-
scala.reflect.OptManifest
는 더 이상 지원되지 않음Tag
가 임의의 타입도 구체화(reify) 할 수 있기 때문
-
scala.reflect.AnyValManifest
와 같은 일을 하는것도 없다- 대신, 자신의 태그를 기본태그(동반 객체에 정의된)중 하나와 비교하여 그것이 primitive value 클래스인지 여부를 알 수 있음
- 또한,
<tag>.tpe.typeSymbol.isprimitiveValueClass
를 통해 간단히 알 수 있음
-
Manifest의 동반 객체에 정의된 factory method들의 대체자도 없음
- 대신, Java(for classes)나 Scala(for tyeps)에서 제공하는 reflection API를 통해 해당 유형을 생성 가능
-
<:<
나>:>
같은 Manifest 관련 특정 연산자도 지원되지 않음- Java, Scala의 reflection API를 사용
-
Scala 2.10에서
scala.reflect.ClassManifest
는 deprecate 됨 -
scala.reflect.Manifest
대신TypeTag
및ClassTag
를 사용 권장하며 향후 릴리즈에서 deprecate 예정 -
Manifest
-based API를Tag
를 사용하도록 변경 권장
위 글은 Scala Documentation의 글을 일부 편집하여 한글로 정리한 것임