如何从具有类型成员的特征转换为具有类型参数的案例类反之亦然

时间:2017-11-02 16:17:07

标签: scala implicit-conversion typeclass

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

我有一个带有一些类型参数的case类(Operation),这个类可以由一个对参数类型一无所知的方法返回(例如来自string / {{1}的解析器} / json)。

所以我需要一种以某种方式从xml转换为ShadowedOperation的方法,因为需要从一些数据中解析Operation并从此提取出类型版本( ShadowedOperation)。

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

可能Operation有一个解决方案,但我需要找到一个没有它的解决方案。

shapeless

提前感谢所有可以提供帮助的人!

1 个答案:

答案 0 :(得分:1)

我做了一些改变:

  • Transform[-A, +B]增加了协方差/逆差

  • 介绍了类型ShadowedOperation.Aux[I0, O0]

  • 使用fakeParseFromString修复Aux的返回类型 - 类型

  • 将案例类的伴随对象中的operationToString提升为具有相应更改的特征的伴随对象

  • 导入的实例: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[???, ???]时,你会丢失一些关于类型的信息。您必须找到一种方法来恢复有关IO(某些转换,明确指定类型,定义更多含义等)的信息。否则暗示不会起作用。

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

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