【发布时间】:2016-04-12 17:40:59
【问题描述】:
使用 shapeless,可以使用 LabelledGeneric 更新案例类字段,如下所示:
case class Test(id: Option[Long], name: String)
val test = Test(None, "Name")
val gen = LabelledGeneric[Test]
scala> gen.from(gen.to(test) + ('id ->> Option(1L)))
res0: Test = Test(Some(1),Name)
我希望Test 类(和其他类)扩展一个抽象类Model,它将实现一个方法withId,该方法将使用类似于上述代码的LabelledGeneric 来更新id字段,它应该有一个(它应该)。
我的尝试将LabelledGeneric[A] 的隐式参数添加到Model 的构造函数中,实现得很好。我还需要以某种方式为 LabelledGeneric#Repr 具有要替换的 id 字段的记录语法提供证据。给withId添加一个隐式的Updater参数满足编译器,这样下面的代码就可以编译了,但是不能用。
import shapeless._, record._, ops.record._, labelled._, syntax.singleton._, tag._
abstract class Model[A](implicit gen: LabelledGeneric[A] { type Repr <: HList }) { this: A =>
def id: Option[Long]
val idWitness = Witness("id")
type F = FieldType[Symbol with Tagged[idWitness.T], Option[Long]]
def withId(id: Long)(implicit u: Updater.Aux[gen.Repr, F, gen.Repr]) =
gen.from(gen.to(this) + ('id ->> Option(id)))
}
case class Test(id: Option[Long], name: String) extends Model[Test]
调用test.withId(1) 时,隐含的Updater 无法实现。宏报告 gen.Repr 不是 HList 类型,而实际上它是。似乎this match 是失败的,其中u baseType HConsSym 返回<notype>。相当于:
scala> weakTypeOf[test.gen.Repr].baseType(weakTypeOf[::[_, _]].typeConstructor.typeSymbol)
res12: reflect.runtime.universe.Type = <notype>
这是使用 shapeless 2.3,尽管它在 2.2 中由于不同的原因而失败(似乎Updater 进行了很大的重构)。
有没有可能用 shapeless 来完成这个,还是我偏离了目标?
【问题讨论】: