Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 案例类-使用转换复制多个字段_Scala_Generics_Shapeless_Case Class - Fatal编程技术网

Scala 案例类-使用转换复制多个字段

Scala 案例类-使用转换复制多个字段,scala,generics,shapeless,case-class,Scala,Generics,Shapeless,Case Class,我有一个包含25个字段的case类,需要将其转换为另一个包含22个字段的case类,其中19个字段是共享的,3个字段是简单重命名的 我已经找到了一些如何使用无形状实现这一点的示例(例如,以及Miles Sabin和的一些代码示例),但最后一个示例看起来有些过时,我无法从Github示例中了解如何使用无形状重命名多个字段,或者在将字段添加到新对象之前对其进行更多操作。有人能帮我吗 简化代码示例 import shapeless.LabelledGeneric case class A(fieldA

我有一个包含25个字段的case类,需要将其转换为另一个包含22个字段的case类,其中19个字段是共享的,3个字段是简单重命名的

我已经找到了一些如何使用
无形状
实现这一点的示例(例如,以及Miles Sabin和的一些代码示例),但最后一个示例看起来有些过时,我无法从Github示例中了解如何使用无形状重命名多个字段,或者在将字段添加到新对象之前对其进行更多操作。有人能帮我吗

简化代码示例

import shapeless.LabelledGeneric
case class A(fieldA:Int, fieldB:String, fieldC:String)
case class B(fieldARenamed:Int, fieldB:String, fieldC:String, fieldCTransformed:String)

val aGen = LabelledGeneric[A]
val bGen = LabelledGeneric[B]

val freddie = new A(1,"Freddie","somestring")

val record = aGen.to(freddie)
val atmp = freddie.fieldA
record.Remove("fielda")

val freddieB = bGen.from(record + 
  (Symbol("fieldARenamed") ->> atmp) +
  (Symbol("fieldCTransformed") ->> freddie.fieldC.toUpperCase)
) //Errors everywhere, even if I replace + with :: etc.
我有一种感觉,
Align
将出现在这里的某个地方,但了解如何以尽可能精简的方式做到这一点——例如,不创建像上面第三个链接那样的额外特征,如
字段
——将是很有趣的

在中,还有一些单引号的用法,(例如,
'fieldC
)表示法,我还没有找到太多相关信息,因此如果这起到了作用,一些解释也会非常有用。对于Scala巫术的这种深度来说是相当新的,所以如果这个问题显得迟钝或涉及太多不同的话题,我深表歉意

编辑:为免生疑问,我不是在寻找答案,这些答案表明我只是通过引用第一个字段手动创建一个新的案例类,如中所示

val freddieB = B(fieldARenamed = freddie.fieldA, fieldB = freddie.fieldB, fieldC = freddie.fieldC, fieldCTransformed =freddie.fieldC.toUpperCase)

请参阅下面的注释,了解其不合适的原因。

最简单的解决方案是使用旧的
案例类的值构造新的
案例类的实例,并根据需要将函数应用于这些值。代码将非常高效,代码的目的将非常明确,它将比任何其他解决方案花费更少的时间来编写,它将比依赖于第三方库的解决方案更加健壮和可维护,并且它避免了两个类之间隐藏的依赖关系。

另一个选项是使用;特别是功能

对于您的特定示例,它将如下所示:

import io.bfil.automapper._

case class A(fieldA:Int, fieldB:String, fieldC:String)
case class B(fieldARenamed:Int, fieldB:String, fieldC:String, fieldCTransformed:String)

val freddie = new A(1,"Freddie","somestring")

val freddieB = automap(freddie).dynamicallyTo[B](
  fieldARenamed = freddie.fieldA, 
  fieldCTransformed = freddie.fieldC.toUpperCase
)
我想你可以把它变成一个函数

def atob(a: A): B = {
  automap(a).dynamicallyTo[B](
    fieldARenamed = a.fieldA, 
    fieldCTransformed = a.fieldC.toUpperCase
  )
}

从效率的角度来看,这个库使用宏,因此实际上与手工编写的一样好

仅供参考,下面是一种让问题代码正常工作的方法

import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.{Align,Intersection}
import shapeless.syntax.singleton._

case class A(fieldA:Int, fieldB:String, fieldC:String)
case class B(fieldARenamed:Int, fieldB:String, fieldC:String, fieldCTransformed:String)

val fromGen = LabelledGeneric[A]
val toGen   = LabelledGeneric[B]

val freddie = A(1, "Freddie", "somestring")
val putARename = Symbol("fieldARenamed")     ->> freddie.fieldA
val putCTrans  = Symbol("fieldCTransformed") ->> freddie.fieldC.toUpperCase

trait Field { type K; type V; type F = FieldType[K, V] }
object Field {
  def apply[K0,V0](sample: FieldType[K0,V0]) =
    new Field { type K = K0; type V = V0 }
}

val pFieldA  = Field(putARename)
val pFieldCT = Field(putCTrans)

val inter = Intersection[pFieldA.F :: pFieldCT.F :: fromGen.Repr, toGen.Repr]
val align = Align[inter.Out, toGen.Repr]

toGen.from(align(inter(putARename :: putCTrans :: fromGen.to(freddie))))
//res0: B = B(1,Freddie,somestring,SOMESTRING)

你能分享你的类吗?上面已经有一个简化的代码示例。shapeless有一个案例研究(6.3),它可以满足你的大部分需求。它不会将现有值转移/转换为新的或重命名的字段。这种事情是可以做到的,但我不知道是否可以推广。字段名称和类型必须在编译时已知,因此您最终会编写大量特定于
a
-to-
B
转换的代码,并且只针对
a
-to-
B
转换。这是我当前的解决方案。然而,考虑到它会导致键入25个字段,它不是很优雅。此外,这些案例类是从数据库模式自动生成的。如果数据库发生更改,我希望能够在不接触代码的情况下更改这些字段(假设对数据库的更改不接触两个case类之间通用的字段,因此不受代码的操纵)。此外,向下投票,问题很清楚,我想要一个答案,使用
无形状的
(或至少类似的东西)复制共享字段,而不显式地键入每个字段。当您创建一个包含25个字段的
案例类时,优雅消失了;花哨的库和晦涩难懂的代码不会让优雅重现。现实世界中有些代码与数据库交互:)包含25个字段的数据库记录也不优雅!谈到现实世界,对数据库的任何更改都需要进行重大审查,并重新编写大量测试,因此,在这段代码中编辑几行代码真的不是什么大不了的事。不是没有形状的,而是放在后口袋里的一个很好的选择。仍然需要比我希望的更多的样板文件,但标记为答案,因为我认为这是我们将得到的最接近的答案。