복붙노트

[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. ==============================

    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. ==============================

    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. ==============================

    3.함수 정의

    함수 정의

    def tt[A : TypeTag](a: A) = typeTag[A]
    

    글을 쓰는 또 다른 방법입니다

    def tt(a: A)(implicit tag: TypeTag[A]) = tag
    

    이는 태그의 예는 컴파일러에 의해 암시 적으로 생성되는 것을 의미한다. 이 뒤에 이유는 스칼라 컴파일러가 그렇지 않으면 삭제 타입 정보를 하드 코딩하여 JVM의 형태 삭제 문제를 해결할 수 있다는 것입니다.

    혹시 유형의 삭제 문제에 익숙하지 않은, 그것은 JVM은 [설정 [지능] JVM에 의해 서열 단순히 볼 [_] 될 것이며, 예를 들어, 형식 서열을 유형 매개 변수 정보가 저장하지 않는다는 것입니다 당신이 반사 누락 된 유형의 정보를 찾을 수있는 방법 없을 것이다.

  4. ==============================

    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]
        }
      })
    }
    
  5. from https://stackoverflow.com/questions/11494788/how-to-create-a-typetag-manually by cc-by-sa and MIT license