【问题标题】:Get type parameters from generic type argument and use in recursive function call从泛型类型参数中获取类型参数并在递归函数调用中使用
【发布时间】:2015-08-12 15:57:45
【问题描述】:

此代码应该将 JSON 数组或 JSON 对象反序列化到其各自的 scala 类中。我遇到的问题是这条线

case x if x <:< typeOf[Array[_]] => deserialize[TypeTag[_]](s.getJSONArray(i))'

我希望该函数检测 X 类型参数是否是某物的数组,并将该某物作为类型参数传递给递归函数调用。 所以如果我调用deserialize[Array[Int]](JSONArray),它应该返回一个Array[Array[Int]]。我需要以某种方式从Array[Int] 中提取Int 并将其传递给deserialize[???](JSONArray)

def deserialize[X: TypeTag](s: JSONObject): X = {
    val m = ru.runtimeMirror(getClass.getClassLoader)
    val classType = ru.typeOf[X].typeSymbol.asClass
    val cm = m.reflectClass(classType)
    val constructor = typeTag.tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
    val constructorMethod = cm.reflectConstructor(constructor)

    val params = constructor.asMethod.paramLists.head
    val args = new Array[Any](params.length)

    for(i <- params.indices) {
        val name = params(i).name.decodedName.toString
        println(params(i).typeSignature.toString)
        args(i) = params(i).typeSignature match {
            case t if t =:= typeOf[String] => s.getString(name)
            case t if t =:= typeOf[Int] => s.getInt(name)
            case t if t =:= typeOf[Double] => s.getDouble(name)
            case t if t =:= typeOf[Boolean] => s.getBoolean(name)
            case t if t =:= typeOf[Long] => s.getLong(name)
            case t if t =:= typeOf[Array[_]] => deserialize[WeakTypeTag[_]](s.getJSONArray(name))
            case t => deserialize[t.type](s.getJSONObject(name))
        }
    }

    constructorMethod(args:_*).asInstanceOf[X]
}

def deserialize[X: ClassTag: TypeTag](s: JSONArray): Array[X] = {
    val arr = new Array[X](s.length())
    for(i <- 0 until s.length) {
        arr(i) = (typeOf[X] match {
            case x if x =:= typeOf[String] => s.getString(i)
            case x if x =:= typeOf[Int] => s.getInt(i)
            case x if x =:= typeOf[Double] => s.getInt(i)
            case x if x =:= typeOf[Boolean] => s.getInt(i)
            case x if x =:= typeOf[Long] => s.getInt(i)
            case x if x <:< typeOf[Array[_]] => deserialize[TypeTag[_]](s.getJSONArray(i))
            case x => deserialize[X](s.getJSONObject(i))
        }).asInstanceOf[X]
    }
    arr
}

【问题讨论】:

  • @Markuse1189 感谢您的编辑。我花了很长时间试图弄清楚为什么反引号格式对我不起作用。

标签: scala generics recursion reflection types


【解决方案1】:

所以虽然我不太明白它为什么会起作用,但我能够根据一堆其他 stackoverflow 问题一起破解一个可行的解决方案。

def deserialize[X](s: JSONObject)(implicit tTag: TypeTag[X]): X = {
    val m = ru.runtimeMirror(getClass.getClassLoader)
    val classType = ru.typeOf[X].typeSymbol.asClass
    val cm = m.reflectClass(classType)
    val constructor = typeTag.tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
    val constructorMethod = cm.reflectConstructor(constructor)

    val params = constructor.asMethod.paramLists.head
    val args = new Array[Any](params.length)

    for(i <- params.indices) {
        val name = params(i).name.decodedName.toString
        args(i) = params(i).typeSignature match {
            case t if t =:= typeOf[String] => s.getString(name)
            case t if t =:= typeOf[Int] => s.getInt(name)
            case t if t =:= typeOf[Double] => s.getDouble(name)
            case t if t =:= typeOf[Boolean] => s.getBoolean(name)
            case t if t =:= typeOf[Long] => s.getLong(name)
            case t if t <:< typeOf[Array[_]] => {
                deserialize(s.getJSONArray(name))(getSubInfo(0)(typeToTypeTag(t, m)))
            }
            case t => deserialize(s.getJSONObject(name))(typeToTypeTag(t, m))
        }
    }

    constructorMethod(args:_*).asInstanceOf[X]
}

def deserialize[X](s: JSONArray)(implicit tTag: TypeTag[X]): Array[X] = {
    val mirror = runtimeMirror(getClass.getClassLoader)
    implicit val xClassTag = ClassTag[X](mirror.runtimeClass(tTag.tpe))

    val arr = new Array[X](s.length())

    for(i <- 0 until s.length) {
        arr(i) = (typeOf[X] match {
            case x if x =:= typeOf[String] => s.getString(i)
            case x if x =:= typeOf[Int] => s.getInt(i)
            case x if x =:= typeOf[Double] => s.getInt(i)
            case x if x =:= typeOf[Boolean] => s.getInt(i)
            case x if x =:= typeOf[Long] => s.getInt(i)
            case x if x <:< typeOf[Array[_]] => {
                deserialize(s.getJSONArray(i))(getSubInfo[X](0))
            }
            case x => {
                deserialize[X](s.getJSONObject(i))
            }
        }).asInstanceOf[X]
    }
    arr
}

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]
        }
    })
}

def getSubInfo[X](i: Int)(implicit tTag: TypeTag[X]): TypeTag[_] = {
    typeToTypeTag(tTag.tpe.asInstanceOf[TypeRefApi].args(i), tTag.mirror)
}

解决方案的本质是最后的功能。 getSubInfo[X](i: Int) 将为 i 处的类型参数返回一个 TypeTag。因此,调用 getSubInfoArray[Int] 将返回 Int 的 TypeTag。 typeToTypeTag 以反射#type 作为参数,使用黑魔法创建类型标签。

【讨论】:

    猜你喜欢
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2016-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多