この問題は、複数のクラスを返すことができる任意のAPIで発生しますが、タイプはAny
です。asInstanceOfボイラープレートなしのAny型の混合値の処理
具体例では、組み込みのJSONパーサー(scala.util.parsing.json
)を使用してJSONを処理しています。返される値はMap[String,Any]
です。これは、各JSONキーと値のペアの値が任意のJSON型であるためです。
これらのネストされたMap
から値を抽出するには、タイプテストとキャスティングが必要です。これはかなり醜いです。特に、戻り値の型(String、Double、Map ...など)とは別の複数の関数があり、チェックとキャストに使用されます。
一般的なget[T](...): T
関数が1つだけ必要なので、この定型文を避けてこの型を抽象化することはできますか?
私はTypeTag
を見てきましたが、これまでのところ、戻り値の型ではなく引数の型を抽象化してみました。明確にするために
:返すレガシーインタフェースに対応するため、私はパターンなどのマッチングと非常に良くインタフェースを提供する他の多くのJSONパーサーがあることを認識してんだけど、私はリファクタリングのこの一般的な問題でちょうど興味Any
のコレクション。
import scala.util.parsing.json._
object ParseJSON {
val text = """{"str":"A String", "num":123, "obj": { "inner":"value" }}"""
val json = JSON.parseFull(text).get.asInstanceOf[Map[String,Any]]
//> ... Map(str -> A String, num -> 123.0, obj -> Map(inner -> value))
// Three essentially identical functions:
def getString(m:Map[String,Any], k:String): Option[String] = {
m.get(k).flatMap{ v =>
if (v.isInstanceOf[String]) Some(v.asInstanceOf[String]) else None
}
}
def getDouble(m:Map[String,Any], k:String): Option[Double] = {
m.get(k).flatMap{ v =>
if (v.isInstanceOf[Double]) Some(v.asInstanceOf[Double]) else None
}
}
def getObject(m:Map[String,Any], k:String): Option[Map[String, Any]] = {
m.get(k).flatMap{ v =>
if (v.isInstanceOf[Map[_,_]]) Some(v.asInstanceOf[Map[String,Any]])
else None
}
}
getString(json, "str") //> res0: Option[String] = Some(A String)
getString(json, "num") //> res1: Option[String] = None
getObject(json, "obj")
//> res3: Option[Map[String,Any]] = Some(Map(inner -> value))
}
私は当初、これは一般的なクラスを経由して解決することができると思っていた:
class Getter[T] {
def get(m: Map[String, Any], k: String): Option[T] = {
m.get(k).flatMap { v =>
if (v.isInstanceOf[T]) Some(v.asInstanceOf[T]) else None
}
}
}
new Getter[String].get(json, "str")
が、オレグPyzhcovは(私の今-削除の回答で)指摘したように、型消去がタイプかどうかを検出するから、これを防止実行時に正しいです。
パッケージ 'scala.util.parsing.json'はもはや推奨されません。むしろJSON専用ライブラリを使用する – cchantep
合意 - しかし、私が質問したように、私はこのリファクタリング問題を解決する方法に興味があります(動機付けの例としてJSON解析を使用) – DNA
落胆したlibの修正制限は非常に小さい – cchantep