如何从具有类型成员的特征转换为具有类型参数的案例类,反之亦然 [英] How convert from trait with type member to case class with type parameter an viceversa
问题描述
我不知道如何解决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.
可能是
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屋!