如何从具有类型成员的特征转换为具有类型参数的案例类,反之亦然 [英] How convert from trait with type member to case class with type parameter an viceversa

查看:62
本文介绍了如何从具有类型成员的特征转换为具有类型参数的案例类,反之亦然的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何解决Scala中的问题.也许有人可以帮助我!

I don't know how to solve a problem in scala. Maybe someone can help me!

我有一个带有某种类型参数的case类( Operation ),该类可以由对参数类型一无所知的方法返回(例如,来自 string / json / xml ).

I have a case class (Operation) with some type parameter, this class can be returned by a method that know nothing about the parameter types (example a parser from string/json/xml).

所以我需要一种以某种方式从 ShadowedOperation 转换为 Operation 的方法,因为需要从某些数据中解析 ShadowedOperation 并从中提取键入的版本( Operation ).

So I need a way to transform from ShadowedOperation to Operation in some way, because the need is to parse from some data a ShadowedOperation and from this extract the typed version (an Operation).

我已经编写了一个可以表达问题的代码,它经过简化,并尝试做一些不同的事情,但是如果可以解决,我也可以解决真正的需求.

I've write a code that should express the problem, it's simplified and try to do something different, but if this can be solved I can solve also the real need.

可能是 shapeless 的解决方案,但我需要找到一个没有它的解决方案.

Probably with shapeless there is a solution, but I need to find a solution without it.

object box {

  trait Transform[A, B] {
    def apply(in: A): B
  }
  object Transform {
    def instance[A, B](f: A => B): Transform[A, B] = new Transform[A, B] {
      override def apply(in: A): B = f(in)
    }
  }

  implicit class TransformOps[T](w: T) {
    def transform(implicit t: Transform[T, String]) = t(w)
  }

  trait ShadowedOperation {
    type I
    type O
    def param: String
    def otherParam: Int
    def in: I
    def out: O
  }

  object ShadowedOperation {
    // How can i do this in a generic, typed and wonderful way ???
    implicit def operationToString: Transform[ShadowedOperation, String] = ???
  }

  case class Operation[I0, O0](
    param: String,
    otherParam: Int,
    in: I0,
    out: O0
  ) extends ShadowedOperation {type I = I0; type O = O0}

  object Operation {
    implicit def operationToString[I, O](
      implicit
      iToString: Transform[I, String],
      oToString: Transform[O, String]
    ): Transform[Operation[I, O], String] =
      Transform.instance(in => s"${in.otherParam} - ${in.param} - ${iToString(in.in)} - ${oToString(in.out)}")
  }

  def fakeParseFromString(in: String): List[ShadowedOperation] = {
    // this simulate a parsing (or read from db) from string to extract the case class
    List(Operation("param", 0, "in!", "out!"), Operation("param", 0, "in!", 100))
  }

}


object Main extends App {

  import box._

  implicit val intToString: Transform[Int, String] = Transform.instance(_.toString)
  implicit val stringToString: Transform[String, String] = Transform.instance(_.toString)

  val op = Operation("param", 0, "in!", "out!")
  val shadowedOperationList = fakeParseFromString("imagine that this string contain a json")
  val opString = op.transform
  val shadowedOpString = shadowedOperationList.map(_.transform)
  println(opString)
  println(shadowedOpString)
}

在此先感谢所有可以提供帮助的人!

Thanks in advance to all who can help!

推荐答案

我做了几处更改:

  • Transform [-A,+ B]

引入了类型 ShadowedOperation.Aux [I0,O0]

使用 Aux -type

operationToString 从案例类的伴随对象提升到具有相应变化的特征伴随对象

lifted operationToString from companion object of case class to companion object of trait with corresponding changes

导入的实例: import op ._

整个代码:

  object box {

    trait Transform[-A, +B] {
      def apply(in: A): B
    }
    object Transform {
      def instance[A, B](f: A => B): Transform[A, B] = new Transform[A, B] {
        override def apply(in: A): B = f(in)
      }
    }

    implicit class TransformOps[T](w: T) {
      def transform(implicit t: Transform[T, String]) = t(w)
    }

    trait ShadowedOperation {
      type I
      type O
      def param: String
      def otherParam: Int
      def in: I
      def out: O

      implicit def operationToString(
                                      implicit
                                      iToString: Transform[I, String],
                                      oToString: Transform[O, String]
                                    ): Transform[ShadowedOperation.Aux[I, O], String] =
        Transform.instance(in => s"${in.otherParam} - ${in.param} - ${iToString(in.in)} - ${oToString(in.out)}")
    }

    object ShadowedOperation {
      type Aux[I0, O0] = ShadowedOperation { type I = I0; type O = O0 }
    }

    case class Operation[I0, O0](
                                  param: String,
                                  otherParam: Int,
                                  in: I0,
                                  out: O0
                                ) extends ShadowedOperation {type I = I0; type O = O0}


    def fakeParseFromString[I, O](in: Operation[I, O]): ShadowedOperation.Aux[I, O] = in

  }




  def main(args: Array[String]): Unit = {
    import box._

    implicit val intToString: Transform[Int, String] = Transform.instance(_.toString)
    implicit val stringToString: Transform[String, String] = Transform.instance(_.toString)

    val op = Operation("param", 0, "in!", "out!")
    val shadowedOperation = fakeParseFromString(op)
    import op._
    val opString = op.transform
    val shadowedOpString = shadowedOperation.transform
    println(opString)//0 - param - in! - out!
    println(shadowedOpString)//0 - param - in! - out!
  }

因此,这里不需要 shapeless .

仅编写 ShadowedOperation 而不是 ShadowedOperation.Aux [???,???] 时,您会丢失一些有关类型的信息.您必须找到一种方法来恢复有关 I O 的信息(某些转换,显式指定类型,定义更多隐式对象等).否则,隐式将不起作用.

When you write just ShadowedOperation instead of ShadowedOperation.Aux[???, ???] you loose some information about types. You have to find a way to restore this information about I, O (some casting, specifying types explicitly, defining more implicits etc.). Otherwise implicits won't work.

例如,在您更新的示例中,您可以编写

For instance in your updated example you can write

def fakeParseFromString(in: String): List[ShadowedOperation.Aux[String, Any]] = 
  List(Operation("param", 0, "in!","out!"), Operation("param", 0, "in!", 100))

implicit val anyToString: Transform[Any, String] = Transform.instance(_.toString)
val shadowedOpString = shadowedOperationList.map(_.transform)
println(shadowedOpString) 
// List(Operation(param,0,in!,out!), Operation(param,0,in!,100))

这篇关于如何从具有类型成员的特征转换为具有类型参数的案例类,反之亦然的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆