복붙노트

[SCALA] 가져 오기 TypeTag [A] 클래스에서 [A]

SCALA

가져 오기 TypeTag [A] 클래스에서 [A]

나는 오버라이드 (override) 할 필요가 createOld 방법이 있고 나는 그것을 변경할 수 없습니다. 나는 createNew에서 패턴 일치 제공 유형에 TypeTag를 사용하고 싶습니다. 목표는 createOld에서 createNew를 호출하는 방법을 찾는 것입니다. 나의 현재 이해는 이미 TypeTag [A]와 함께 제공되지 않는 경우에 그 컴파일러는 createOld 방법에 대해 충분히 유형 정보가없는 것입니다.

object TypeTagFromClass {
  class C1
  class C2

  // How to get TypeTag[A] needed by createNew?
  def createOld[A](c: Class[A]): A = createNew ???

  def createNew[A : TypeTag]: A = {
    val result = typeOf[A] match {
      case a if a =:= typeOf[C1] => new C1()
      case a if a =:= typeOf[C2] => new C2()
    }
    result.asInstanceOf[A]
  }
}

해결법

  1. ==============================

    1.나는 확실하지 TypeCreator의이 구현은 절대적으로 맞다면 해요하지만 스칼라 반사를 사용하여 클래스에서 TypeTag을 만들 수 있습니다 :

    나는 확실하지 TypeCreator의이 구현은 절대적으로 맞다면 해요하지만 스칼라 반사를 사용하여 클래스에서 TypeTag을 만들 수 있습니다 :

    import scala.reflect.runtime.universe._
    
    def createOld[A](c: Class[A]): A = createNew {
      val mirror = runtimeMirror(c.getClassLoader)  // obtain runtime mirror
      val sym = mirror.staticClass(c.getName)  // obtain class symbol for `c`
      val tpe = sym.selfType  // obtain type object for `c`
      // create a type tag which contains above type object
      TypeTag(mirror, new TypeCreator {
        def apply[U <: Universe with Singleton](m: api.Mirror[U]) =
          if (m eq mirror) tpe.asInstanceOf[U # Type]
          else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
      })    
    }
    

    당신이 일반적인 매개 변수와 전체 스칼라 유형 정보를 검사 할 필요가없는 경우, 당신은 정말 전체 TypeTag 필요하지 않습니다. 당신은 그것에 대해 ClassTags을 사용할 수 있습니다 :

    def createNew[A: ClassTag]: A = {
      val result = classTag[A].runtimeClass match {
        case a if a.isAssignableFrom(classOf[C1]) => new C1()
        case a if a.isAssignableFrom(classOf[C2]) => new C2()
      }
      result.asInstanceOf[A]
    }
    

    또는 어떤 암시 설탕 :

    implicit class ClassTagOps[T](val classTag: ClassTag[T]) extends AnyVal {
      def <<:(other: ClassTag[_]) = classTag.runtimeClass.isAssignableFrom(other.runtimeClass)
    }
    
    def createNew[A: ClassTag]: A = {
      val result = classTag[A] match {
        case a if a <<: classTag[C1] => new C1()
        case a if a <<: classTag[C2] => new C2()
      }
      result.asInstanceOf[A]
    }
    

    당신은 평범한 구식 자바 위해서, newInstance () 메소드를 사용하여 더욱 그를 단순화 할 수 있습니다 :

    def createNew[A: ClassTag]: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
    

    서로 다른 클래스의 다른 생성자의 매개 변수가 필요하지 않은 경우 이것은 물론에만 작동합니다.

    createOld에서이 createNew를 호출하면 TypeTags와 함께보다 훨씬 간단합니다 :

    def createOld[A](c: Class[A]): A = createNew(ClassTag[A](c))
    
  2. ==============================

    2.다음과 같은 작업을 수행 할 (당신의 논리를 사용하여) (당신이 스칼라 형식 시스템의 전원을 사용하지 않는 원인),하지만 당신은 할 수 있습니다 매우 안전하고 정확하지 않습니다 그래서 :

    다음과 같은 작업을 수행 할 (당신의 논리를 사용하여) (당신이 스칼라 형식 시스템의 전원을 사용하지 않는 원인),하지만 당신은 할 수 있습니다 매우 안전하고 정확하지 않습니다 그래서 :

    def createNew[A](implicit t: TypeTag[A]): A = {
      val result: Any = t.tpe.toString match {
        case "C1" => new C1
        case "C2" => new C2
      }
      result.asInstanceOf[A]
    }
    
    createNew[C1] //> its all ok
    createNew[C2] //> its all ok
    createNew[C3] //> crashes here; lets pretend we got C3 class
    

    createOld와 함께 사용하려면 단지 암시 인수를 전달 :

    def createOld[A](c: Class[A])(implicit t: TypeTag[A]): A = createNew[A]
    
    createOld[C1] //> its all ok
    createOld[C2] //> its all ok
    createOld[C3] //> crashes here; lets pretend we got C3 class
    

    나는 그것을 아주 좋은 아니라는 것을 두 번 당신에게 말할한다고 생각합니다. 우리는 볼품를 사용하여이 코드를 향상시킬 수 있습니다 :

    인수로 TypeTag이있는 폴리 함수를 만들 수 있습니다 :

     import shapeless._; import scala.reflect.runtime.universe._;
    
     def getTypeTag[T](implicit t: TypeTag[T]) = t //> to get TypeTag of a class
    
     // here is low prority implicit
     trait createPolyNewErr extends Poly1 {
       implicit def newErr[T] = at[T](_ => "Error can not create object of this class")
     } 
    
     object createPolyBew extends createPolyNewError {
       implicit def newC1 = at[TypeTag[C1]](_ => new C1)
       implicit def newC2 = at[TypeTag[C2]](_ => new C2)
     }
    
     createPolyNew(getTypeTag[C1]) //> success
     createPolyNew(getTypeTag[C2]) //> success
     createPolyNew(getTypeTag[C3]) //> String: Error can not create object of this class no crash!
    

    우리는 또한 사용하지 않을 기능 getTypeTag [T] 모든 시간을 위해, 함수를 작성할 수 있습니다 :

     def createPoly[T]
     (implicit t: TypeTag[T],
             cse: poly.Case[createPolyNew.type, TypeTag[T] :: HNil]) = cse(t)
    
     createPoly[C1] //> its all ok
     createPoly[C2] //> its all ok
     createPoly[C3] //> String: Error can not create object of this class no crash!
    
  3. from https://stackoverflow.com/questions/22970209/get-typetaga-from-classa by cc-by-sa and MIT license