[SCALA] 어떻게 수동으로 TypeTag를 만드는 방법?
SCALA어떻게 수동으로 TypeTag를 만드는 방법?
나는 (2.10M5 때문에) 수동으로 TypeTag를 생성에 관심이 있어요 :
object X {
import reflect.runtime.universe._
def tt[A : TypeTag](a: A) = typeTag[A] // how to do this manually?
val t = tt(List("")(_))
}
scalac -Xprint : TYPER <파일> .scala 결과
package <empty> {
object X extends scala.AnyRef {
def <init>(): X.type = {
X.super.<init>();
()
};
import scala.reflect.runtime.`package`.universe._;
def tt[A >: Nothing <: Any](a: A)(implicit evidence$1: reflect.runtime.universe.TypeTag[A]): reflect.runtime.universe.TypeTag[A] = scala.reflect.runtime.`package`.universe.typeTag[A](evidence$1);
private[this] val t: reflect.runtime.universe.TypeTag[Int => String] = X.this.tt[Int => String](((x$1: Int) => immutable.this.List.apply[String]("").apply(x$1)))({
val $u: reflect.runtime.universe.type = scala.this.reflect.runtime.`package`.universe;
val $m: $u.Mirror = scala.this.reflect.runtime.`package`.universe.runtimeMirror(this.getClass().getClassLoader());
$u.TypeTag.apply[Int => String]($m, {
final class $typecreator1 extends TypeCreator {
def <init>(): $typecreator1 = {
$typecreator1.super.<init>();
()
};
def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = {
val $u: U = $m$untyped.universe;
val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
$u.TypeRef.apply($u.ThisType.apply($m.staticModule("scala").asModuleSymbol.moduleClass), $m.staticClass("scala.Function1"), scala.collection.immutable.List.apply[$u.Type]($m.staticClass("scala.Int").asTypeSymbol.asTypeConstructor, $m.staticClass("java.lang.String").asTypeSymbol.asTypeConstructor))
}
};
new $typecreator1()
})
});
<stable> <accessor> def t: reflect.runtime.universe.TypeTag[Int => String] = X.this.t
}
}
이 유형은 하드 코딩되어 있기 때문에 완전히 컴파일러 마법 것으로 보인다. 그럼에도 불구하고이 수동으로 할 수있는 방법이 있나요?
해결법
-
==============================
1.M3에서 당신은 매우 간단한 방법으로 형 태그를 만들 수 있습니다, 예컨대 : TypeTag [지능] (TypeRef (<스칼라 패키지>, 무기 호)
). 그것은 기본적으로 유형 태그가 생성되면, 그것은 영원히 특정 클래스 로더 (위의 예제에서 scala.Int의 상징을로드하는 데 사용되었다 즉 하나)에 결합되는 것을 의미한다. M3에서 당신은 매우 간단한 방법으로 형 태그를 만들 수 있습니다, 예컨대 : TypeTag [지능] (TypeRef (<스칼라 패키지>, 무기 호)
). 그것은 기본적으로 유형 태그가 생성되면, 그것은 영원히 특정 클래스 로더 (위의 예제에서 scala.Int의 상징을로드하는 데 사용되었다 즉 하나)에 결합되는 것을 의미한다. 우리는 우리가 모든 클래스 로더를 수용합니다 획일적 인 거울을 가질 수 있다고 생각하기 때문에 그때는 괜찮습니다. 그냥 암시 적으로 쓸 수 있기 때문에 편리했다 [TypeTag [T]]와 컴파일러가 요청한 타입을 인스턴스화하는 글로벌 거울을 사용합니다.
각각 자신의 클래스 로더를 가진 - 불행하게도 나중에, 의견을 바탕으로, 우리는이 일을하지 않을 것을, 우리는 여러 개의 거울이 필요하다는 것을 깨달았다.
그리고 그것은 유형 태그를 사용하려는 클래스 로더 어떤 것을 암시 [TypeTag [T]] 컴파일러가없는 충분한 정보를 기록하면 때문에, 유연 할 필요가 명백하게되었다. 1) 메이크업 형 태그 할 수있는,이 명시 적으로 형 공장에 입력 한 태그), 유형 태그 컴파일러에서 요청할 때마다) (2) 거울을 제공 변환하도록 강요 될 수 있도록 (거울에 경로에 의존 : 기본적으로 두 가지 대안이 있었다 어떤 거울에 자신을 인스턴스화. 우리가 어디 우리가 그래서 길고도 짧은 이야기, 첫 번째 옵션은없는 일을했다.
그래서 현재 https://github.com/scala/scala/blob/master/src/library/scala/reflect/base/TypeTags.scala#L143에 설명 된대로 태그, 꽤 로터리 방식으로 작성해야 입력합니다. 당신은 동반자 TypeTag에 정의 된 팩토리 메소드를 호출하고 두 개의 인수 제공 : 1) 유형의 태그가 인스턴스화 될 기본 미러, 2) 임의의 거울 형태의 태그를 인스턴스화 할 수있는 유형의 공장. 이 컴파일러는 위의 첨부했습니다 인쇄물에 무슨 짓을 기본적으로.
왜이 원형 교차로라고? 유형 공장을 제공하기 때문에 사용자가 수동으로 scala.reflect.base.TypeFactory 클래스를 서브 클래 싱해야합니다. 즉, 기능 및 입력 - 의존적 방식의 경계에 스칼라 타입 시스템의 불행 제한이다.
-
==============================
2.가져 오기 TypeTag을 바탕으로 [A] 클래스 [A]에서 :
가져 오기 TypeTag을 바탕으로 [A] 클래스 [A]에서 :
import scala.reflect.runtime.universe._ def typeToTypeTag[T]( tpe: Type, mirror: reflect.api.Mirror[reflect.runtime.universe.type] ): TypeTag[T] = { TypeTag(mirror, new reflect.api.TypeCreator { def apply[U <: reflect.api.Universe with Singleton](m: reflect.api.Mirror[U]) = { assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.") tpe.asInstanceOf[U#Type] } }) }
예를 들어이 다른 TypeTag의 일부에 대한 TypeTag을 가져올 수 있습니다 :
def inside[A, B](tag: TypeTag[(A, B)]): (TypeTag[A], TypeTag[B]) = { val tpes = tag.tpe.asInstanceOf[TypeRefApi].args val tagA = typeToTypeTag[A](tpes(0), tag.mirror) val tagB = typeToTypeTag[B](tpes(1), tag.mirror) return (tagA, tagB) }
이 스칼라 2.10.2에서 작동 :
scala> inside(typeTag[(Int, Double)]) res0: (reflect.runtime.universe.TypeTag[Int], reflect.runtime.universe.TypeTag[Double]) = (TypeTag[Int],TypeTag[Double])
특정 미러에 연결되는 제한은 한 여러 클래스 로더를하지를 않는 것 문제가되지 않습니다.
-
==============================
3.함수 정의
함수 정의
def tt[A : TypeTag](a: A) = typeTag[A]
글을 쓰는 또 다른 방법입니다
def tt(a: A)(implicit tag: TypeTag[A]) = tag
이는 태그의 예는 컴파일러에 의해 암시 적으로 생성되는 것을 의미한다. 이 뒤에 이유는 스칼라 컴파일러가 그렇지 않으면 삭제 타입 정보를 하드 코딩하여 JVM의 형태 삭제 문제를 해결할 수 있다는 것입니다.
혹시 유형의 삭제 문제에 익숙하지 않은, 그것은 JVM은 [설정 [지능] JVM에 의해 서열 단순히 볼 [_] 될 것이며, 예를 들어, 형식 서열을 유형 매개 변수 정보가 저장하지 않는다는 것입니다 당신이 반사 누락 된 유형의 정보를 찾을 수있는 방법 없을 것이다.
-
==============================
4.현재, 그 지원 제네릭 수동으로 TypeTag을 생성하는 세 가지 방법이 있습니다. 처음 두 스칼라 컴파일러에 의존하고 실제 코드 컴파일이기 때문에 그들과 함께 당신은 단지 컴파일 시간에 같은 유형 검사를 얻을 :
현재, 그 지원 제네릭 수동으로 TypeTag을 생성하는 세 가지 방법이 있습니다. 처음 두 스칼라 컴파일러에 의존하고 실제 코드 컴파일이기 때문에 그들과 함께 당신은 단지 컴파일 시간에 같은 유형 검사를 얻을 :
import scala.reflect.runtime.universe._ import scala.reflect.runtime.currentMirror import scala.tools.reflect.ToolBox val toolbox = currentMirror.mkToolBox() def createTypeTag(tp: String): TypeTag[_] = { val ttree = toolbox.parse(s"scala.reflect.runtime.universe.typeTag[$tp]") toolbox.eval(ttree).asInstanceOf[TypeTag[_]] }
당신이 직렬화 TypeTag이 필요하고 성능이 주요한 문제가 아닌 경우, 첫 번째 방법은 가장 간결하다. 사용 사례의 요구가 매우 확대됨 될 경우 OTOH, 컴파일이 마무리에 몇 초 정도 걸릴 수 있습니다 - 더 - 플라이 것을 조심.
조금 더 나은 두 번째 방법의 수행 :
def createTypeTag(tp: String): TypeTag[_] = { val ttagCall = s"scala.reflect.runtime.universe.typeTag[$tp]" val tpe = toolbox.typecheck(toolbox.parse(ttagCall), toolbox.TYPEmode).tpe.resultType.typeArgs.head TypeTag(currentMirror, new reflect.api.TypeCreator { def apply[U <: reflect.api.Universe with Singleton](m: reflect.api.Mirror[U]) = { assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.") tpe.asInstanceOf[U#Type] } } }
당신의 대상이 목록 [문자열]의 경우 scala.List이기 때문에이 두 번째 모드는 입력 된 트리를 만들고 TypeTag에 표시된 구체적인 유형을 가져 오는, 즉, 그것은, scala.collection.immutable.List [문자열]로 변환됩니다 단지 형 별명입니다. 즉 실제로 typeTag [목록 [문자열]]에서 예상되는 동작입니다.
마지막 방법은 수동으로 유형을 생성하고 TypeTag를 생성하는 데 사용하는 것입니다. 이 방법은 제한된 유형 검사가 에러가 발생하기 쉬운이며 내부 API를 이용한다. 이것은, 그러나, 수동으로 TypeTag를 얻을 수있는 가장 빠른 방법입니다.
def createTypeTag(tp: String): TypeTag[_] = { val typs = // ... manipulate the string to extract type and parameters val typSym = currentMirror.staticClass(typs[0]) val paramSym = currentMirror.staticClass(typs[1]) val tpe = universe.internal.typeRef(NoPrefix, typSym, List(paramSym.selfType)) val ttag = TypeTag(currentMirror, new TypeCreator { override def apply[U <: Universe with Singleton](m: Mirror[U]): U#Type = { assert(m == currentMirror, s"TypeTag[$tpe] defined in $currentMirror cannot be migrated to $m.") tpe.asInstanceOf[U#Type] } }) }
from https://stackoverflow.com/questions/11494788/how-to-create-a-typetag-manually by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라가 예약 된 단어와 자바 라이브러리를 사용하여 (0) | 2019.11.07 |
---|---|
[SCALA] 시계열 스파크에서 작성 격차 (0) | 2019.11.07 |
[SCALA] 스파크 RDD의 배 방법의 설명 (0) | 2019.11.07 |
[SCALA] TimeoutException을 수신 가능한 이유는 무엇입니까 : 선물은 [n 초] 후 시간 초과 스파크로 작업 할 때 [중복] (0) | 2019.11.07 |
[SCALA] 암시 적 변환의 결과 유형은 AnyRef보다 더 구체적이어야합니다 (0) | 2019.11.07 |