[解決済み】TypeTagとは何ですか、どのように使用するのですか?
質問
TypeTagsについて知っているのは、マニフェストに取って代わったということだけです。インターネット上の情報は乏しく、よく理解できません。
そこで、どなたかTypeTagsのサンプルや一般的な使用例を含む有用な資料のリンクを教えていただけると幸いです。また、詳細な回答や説明も歓迎します。
どのように解決するのですか?
A
TypeTag
は、Scalaの型が実行時に消去される問題(type erasure)を解決します。もし
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] = [email protected]#Foo$Bar
scala> val ev2 = m(f2)(b2)
warning: there were 2 deprecation warnings; re-run with -deprecation for details
ev2: Manifest[f2.Bar] = [email protected]#Foo$Bar
scala> ev1 == ev2 // they should be different, thus the result is wrong
res28: Boolean = true
したがって、これらは タイプタグ これは、よりシンプルに使用でき、新しい 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
を期待するメソッドを呼び出すと、そのような
TypeTag
. タグには3種類の形式が存在する。
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]
上で見たように、彼らは型消去を気にしないので、もしquot;full"型が欲しいのなら
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
見てわかるように、メソッド
tpe
の
TypeTag
の結果、完全な
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
???
}
}
を置き換えた場合
WeakTypeTag
で
TypeTag
というエラーが投げられます。
<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]
^
の違いについてのより詳細な説明については、こちらをご覧ください。
TypeTag
と
WeakTypeTag
はこの質問をご覧ください。
Scalaのマクロです。"未解決の型パラメーターを持つ型TからTypeTagを作成できない"
また、Scala の公式ドキュメントサイトには Reflection のガイド .
関連
-
[解決済み] 実行時に変数の型を取得したい
-
[解決済み] C#でお金に使うデータ型は何が良いのか?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] C++のPOD型とは何ですか?
-
[解決済み] Pythonの旧スタイルのクラスと新スタイルのクラスの違いは何ですか?
-
[解決済み] Scalaでファイル全体を読む?
-
[解決済み】type()とisinstance()の違いは何ですか?)
-
[解決済み] Spark SQLでカラムの降順でソートするには?
-
[解決済み] Scalaのパターンマッチングシステムで比較演算子を使う
-
[解決済み】Haskell/GHCの`forall`キーワードは何をするのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Scala forallの例?
-
[解決済み] Scala underscore - ERROR: 展開された関数のパラメータ型が見つかりません。
-
[解決済み] Scala - case classを木のように(きれいに)印刷する方法
-
[解決済み] Scala : valへの再割り当て [重複].
-
[解決済み] Spark - CSVファイルをDataFrameとして読み込む?
-
[解決済み】Scalaの型消去を回避するにはどうしたらいいですか?または、なぜ私のコレクションの型パラメータを取得することができないのですか?
-
[解決済み】ScalaのfoldLeftとreduceLeftの違いについて
-
[解決済み】ScalaでVectorを選択するのはどんなとき?
-
[解決済み] Scalaの==と.equalsの違いは何ですか?
-
[解決済み] ScalaのManifestとは何か、いつ必要なのか?