加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 具有内部案例类的case类的字符串列表

发布时间:2020-12-16 18:09:59 所属栏目:安全 来源:网络整理
导读:假设我有2个案例类: case class Money(amount: Int,currency: String)case class Human(name: String,money: Money) 有没有一种很好的方法可以将一个字符串列表“翻译”为类Human?像: def superMethod[A](params: List[String]): A = ???val params: List
假设我有2个案例类:

case class Money(amount: Int,currency: String)
case class Human(name: String,money: Money)

有没有一种很好的方法可以将一个字符串列表“翻译”为类Human?像:

def superMethod[A](params: List[String]): A = ???

val params: List[Any] = List("john",100,"dollar")
superMethod(params) // => Human("john",Money(100,"dollar"))

所以基本上我只在运行时知道类型A.

更新:我发现?我在寻找什么.看来我可以通过无形来做到这一点. example我在github找到了

解决方法

这是一个适用于泛型类A的实现.

它依赖于运行时反射(也就是说,可以在运行时将不同的TypeTag传递给方法).必须满足以下明显条件才能使用此方法:

> A必须在类路径上,否则可以由使用的类加载器加载
>在呼叫站点,TypeTag必须可用于A.

实际的实现是在Deserializer对象中.然后是一个小小的演示.

解串器:

import scala.reflect.runtime.universe.{TypeTag,Type}

object Deserializer {

  /** Extracts an instance of type `A` from the 
    * flattened `Any` constructor arguments,and returns 
    * the constructed instance together with the remaining
    * unused arguments.
    */
  private def deserializeRecHelper(
    flattened: List[Any],tpe: Type
  ): (Any,List[Any]) = {
    import scala.reflect.runtime.{universe => ru}

    // println("Trying to deserialize " + tpe + " from " + flattened)

    // println("Constructor alternatives: ")
    // val constructorAlternatives = tpe.
    //   member(ru.termNames.CONSTRUCTOR).
    //   asTerm.
    //   alternatives.foreach(println)

    val consSymb = tpe.
      member(ru.termNames.CONSTRUCTOR).
      asTerm.
      alternatives(0).
      asMethod

    val argsTypes: List[Type] = consSymb.paramLists(0).map(_.typeSignature)
    if (tpe =:= ru.typeOf[String] || argsTypes.isEmpty) {
      val h :: t = flattened
      (h,t)
    } else {
      val args_rems: List[(Any,List[Any])] = argsTypes.scanLeft(
        (("throwaway-sentinel-in-deserializeRecHelper": Any),flattened)
      ) { 
        case ((_,remFs),t) => 
        deserializeRecHelper(remFs,t)
      }.tail

      val remaining: List[Any] = args_rems.last._2
      val args: List[Any] = args_rems.unzip._1

      val runtimeMirror = ru.runtimeMirror(getClass.getClassLoader)
      val classMirror = runtimeMirror.reflectClass(tpe.typeSymbol.asClass)
      val cons = classMirror.reflectConstructor(consSymb)

      // println("Build constructor arguments array for " + tpe + " : " + args)

      val obj = cons.apply(args:_*)
      (obj,remaining)
    }
  }

  def deserialize[A: TypeTag](flattened: List[Any]): A = {
    val (a,rem) = deserializeRecHelper(
      flattened,(implicitly: TypeTag[A]).tpe
    )

    require(
      rem.isEmpty,"Superfluous arguments remained after deserialization: " + rem
    )

    a.asInstanceOf[A]
  }
}

演示:

case class Person(id: String,money: Money,pet: Pet,lifeMotto: String)
case class Money(num: Int,currency: String)
case class Pet(color: String,species: Species)
case class Species(description: String,name: String)

object Example {
  def main(args: Array[String]): Unit = {
    val data = List("Bob",42,"USD","pink","invisible","unicorn","what's going on ey?")
    val p = Deserializer.deserialize[Person](data)
    println(p)
  }
}

输出:

Person(Bob,Money(42,USD),Pet(pink,Species(invisible,unicorn)),what's going on ey?)

讨论

此实现不仅限于case类,但它要求每个“Tree-node-like”类只有一个接受它的构造函数

>原始类型(Int,Float),或
>字符串,或
>其他“树节点”类.

请注意,该任务有点不合理:说所有构造函数参数在单个列表中被展平是什么意思?给定Person类(name:String,age:Int),List [Any]是否会将名称的每个字节都包含在一个单独的条目中?可能不是.因此,字符串由解串器以特殊方式处理,并且由于相同的原因而不支持所有其他类似集合的实体(不清楚在何处停止解析,因为集合的大小未知).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读