Programming

스칼라 : TypeTag 란 무엇이며 어떻게 사용합니까?

procodes 2020. 2. 29. 15:34
반응형

스칼라 : TypeTag 란 무엇이며 어떻게 사용합니까?


TypeTag에 대해 내가 아는 전부는 어떻게 든 매니페스트를 대체한다는 것입니다. 인터넷에 관한 정보는 희소하며 그 주제에 대한 올바른 이해를 제공하지 않습니다.

따라서 누군가가 예제 및 널리 사용되는 유스 케이스를 포함하여 TypeTag에 대한 유용한 자료에 대한 링크를 공유하면 기쁠 것입니다. 자세한 답변과 설명도 환영합니다.


A는 TypeTag스칼라의 유형이 런타임 (유형 삭제)에서 삭제되는 문제를 해결합니다. 우리가하고 싶다면

class Foo
class Bar extends Foo

def meth[A](xs: List[A]) = xs match {
  case _: List[String] => "list of strings"
  case _: List[Foo] => "list of foos"
}

우리는 경고를받을 것입니다 :

<console>:23: warning: non-variable type argument String in type pattern List[String]↩
is unchecked since it is eliminated by erasure
         case _: List[String] => "list of strings"
                 ^
<console>:24: warning: non-variable type argument Foo in type pattern List[Foo]↩
is unchecked since it is eliminated by erasure
         case _: List[Foo] => "list of foos"
                 ^

이 문제를 해결하기 위해 매니페스트 가 Scala에 도입되었습니다. 그러나 그들은 경로 의존형과 같은 유용한 유형을 많이 표현할 수 없다는 문제가 있습니다.

scala> class Foo{class Bar}
defined class Foo

scala> def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev
warning: there were 2 deprecation warnings; re-run with -deprecation for details
m: (f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar])Manifest[f.Bar]

scala> val f1 = new Foo;val b1 = new f1.Bar
f1: Foo = Foo@681e731c
b1: f1.Bar = Foo$Bar@271768ab

scala> val f2 = new Foo;val b2 = new f2.Bar
f2: Foo = Foo@3e50039c
b2: f2.Bar = Foo$Bar@771d16b9

scala> val ev1 = m(f1)(b1)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Bar

scala> val ev2 = m(f2)(b2)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Bar

scala> ev1 == ev2 // they should be different, thus the result is wrong
res28: Boolean = true

따라서 TypeTags 로 대체되어 사용이 훨씬 간단하고 새로운 Reflection API에 잘 통합되었습니다. 그것들로 우리는 경로 의존형에 관한 위의 문제를 우아하게 해결할 수 있습니다.

scala> def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev
m: (f: Foo)(b: f.Bar)(implicit ev: reflect.runtime.universe.TypeTag[f.Bar])↩
reflect.runtime.universe.TypeTag[f.Bar]

scala> val ev1 = m(f1)(b1)
ev1: reflect.runtime.universe.TypeTag[f1.Bar] = TypeTag[f1.Bar]

scala> val ev2 = m(f2)(b2)
ev2: reflect.runtime.universe.TypeTag[f2.Bar] = TypeTag[f2.Bar]

scala> ev1 == ev2 // the result is correct, the type tags are different
res30: Boolean = false

scala> ev1.tpe =:= ev2.tpe // this result is correct, too
res31: Boolean = false

또한 유형 매개 변수를 확인하는 데 사용하기도 쉽습니다.

import scala.reflect.runtime.universe._

def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {
  case t if t =:= typeOf[String] => "list of strings"
  case t if t <:< typeOf[Foo] => "list of foos"
}

scala> meth(List("string"))
res67: String = list of strings

scala> meth(List(new Bar))
res68: String = list of foos

이 시점에서 평등 검사에 =:=(유형 평등) 및 <:<(하위 유형 관계) 를 사용하는 것을 이해하는 것이 매우 중요 합니다. 사용하지 마십시오 ==또는 !=당신이 절대적으로 당신이 무엇을 알고하지 않는 :

scala> typeOf[List[java.lang.String]] =:= typeOf[List[Predef.String]]
res71: Boolean = true

scala> typeOf[List[java.lang.String]] == typeOf[List[Predef.String]]
res72: Boolean = false

후자는 구조적 평등을 검사하는데, 이는 접두사와 같은 것을 신경 쓰지 않기 때문에 수행해야 할 일이 아닙니다 (예와 같이).

A TypeTag는 완전히 컴파일러에서 생성됩니다. 즉, 컴파일러 TypeTag는 a를 기대하는 메소드를 호출 할 때 작성하여 작성 합니다 TypeTag. 태그에는 세 가지 형태가 있습니다.

ClassTag대체품 ClassManifest반면 TypeTag에 대한 다소간 대체 Manifest.

전자는 일반 배열을 완전히 사용할 수 있습니다.

scala> import scala.reflect._
import scala.reflect._

scala> def createArr[A](seq: A*) = Array[A](seq: _*)
<console>:22: error: No ClassTag available for A
       def createArr[A](seq: A*) = Array[A](seq: _*)
                                           ^

scala> def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*)
createArr: [A](seq: A*)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]

scala> createArr(1,2,3)
res78: Array[Int] = Array(1, 2, 3)

scala> createArr("a","b","c")
res79: Array[String] = Array(a, b, c)

ClassTag 런타임에 유형을 작성하는 데 필요한 정보 만 제공합니다 (유형이 지워짐).

scala> classTag[Int]
res99: scala.reflect.ClassTag[Int] = ClassTag[int]

scala> classTag[Int].runtimeClass
res100: Class[_] = int

scala> classTag[Int].newArray(3)
res101: Array[Int] = Array(0, 0, 0)

scala> classTag[List[Int]]
res104: scala.reflect.ClassTag[List[Int]] =↩
        ClassTag[class scala.collection.immutable.List]

위에서 볼 수 있듯이 타입 삭제에 신경 쓰지 않으므로 "풀"타입을 원한다면 TypeTag다음을 사용하십시오.

scala> typeTag[List[Int]]
res105: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]

scala> typeTag[List[Int]].tpe
res107: reflect.runtime.universe.Type = scala.List[Int]

scala> typeOf[List[Int]]
res108: reflect.runtime.universe.Type = scala.List[Int]

scala> res107 =:= res108
res109: Boolean = true

하나는, 방법을 볼 수 있듯이 tpeTypeTag전체에 결과를 Type때 우리가 얻을 동일하다, typeOf라고합니다. 물론, 모두를 사용할 수있다, ClassTag그리고 TypeTag:

scala> def m[A : ClassTag : TypeTag] = (classTag[A], typeTag[A])
m: [A](implicit evidence$1: scala.reflect.ClassTag[A],↩
       implicit evidence$2: reflect.runtime.universe.TypeTag[A])↩
      (scala.reflect.ClassTag[A], reflect.runtime.universe.TypeTag[A])

scala> m[List[Int]]
res36: (scala.reflect.ClassTag[List[Int]],↩
        reflect.runtime.universe.TypeTag[List[Int]]) =↩
       (scala.collection.immutable.List,TypeTag[scala.List[Int]])

이제 남은 질문은 어떤 의미 WeakTypeTag입니까? 즉, TypeTag구체적 유형을 나타냅니다 (즉, 완전히 인스턴스화 된 유형 만 허용 함) WeakTypeTag. 대부분의 경우 어떤 것을 TypeTag사용 해야하는지 (어떤 것을 사용 해야하는지) 신경 쓰지 않지만, 예를 들어 매크로가 사용될 때 일반 유형과 작동해야하는 경우에는 다음이 필요합니다.

object Macro {
  import language.experimental.macros
  import scala.reflect.macros.Context

  def anymacro[A](expr: A): String = macro __anymacro[A]

  def __anymacro[A : c.WeakTypeTag](c: Context)(expr: c.Expr[A]): c.Expr[A] = {
    // to get a Type for A the c.WeakTypeTag context bound must be added
    val aType = implicitly[c.WeakTypeTag[A]].tpe
    ???
  }
}

경우 일 명을 대체 WeakTypeTagTypeTag오류가 발생합니다 :

<console>:17: error: macro implementation has wrong shape:
 required: (c: scala.reflect.macros.Context)(expr: c.Expr[A]): c.Expr[String]
 found   : (c: scala.reflect.macros.Context)(expr: c.Expr[A])(implicit evidence$1: c.TypeTag[A]): c.Expr[A]
macro implementations cannot have implicit parameters other than WeakTypeTag evidences
             def anymacro[A](expr: A): String = macro __anymacro[A]
                                                      ^

의 차이점에 대한보다 자세한 설명 TypeTagWeakTypeTag:이 질문에 참조 "해결되지 않은 형식 매개 변수를 갖는 타입 T에서 TypeTag를 만들 수 없습니다": 스칼라 매크로

Scala의 공식 문서 사이트에는 Reflection에 대한 안내서 도 포함되어 있습니다 .

참고 URL : https://stackoverflow.com/questions/12218641/scala-what-is-a-typetag-and-how-do-i-use-it



반응형