Используя shapeless, можно использовать LabelledGeneric
для обновления полей класса case следующим образом:
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
, которое нужно заменить. Добавление неявного параметра Updater
в withId
удовлетворяет компилятор, поэтому приведенный ниже код будет компилироваться, но его нельзя использовать.
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
, хотя на самом деле это так. Похоже, что