我需要生成一个可扩展的记录,给出一个HList
个键和一个值映射,这里是我想要实现的MWE(你可以复制/粘贴任何一个) REPL提供无形2.0,以重现问题)
import shapeless._; import syntax.singleton._; import record._
case class Foo[T](column: Symbol)
val cols = Foo[String]('column1) :: HNil
val values = Map("column1" -> "value1")
object toRecord extends Poly1 {
implicit def Foo[T] = at[Foo[T]] { foo =>
val k = foo.column.name
val v = values.get(k)
(k ->> v)
}
}
val r = cols.map(toRecord)
// r: shapeless.::[Option[String] with shapeless.record.KeyTag[k.type,Option[String]] forSome { val k: String },shapeless.HNil] = Some(value1) :: HNil
val value = r("column1")
// error: No field String("column1") in record shapeless.::[Option[String] with shapeless.record.KeyTag[k.type,Option[String]] forSome { val k: String },shapeless.HNil]
val value = r("column1")
如果我尝试手动定义记录,一切都按预期工作
val q = ("column1" ->> Some("value1")) :: HNil
// q: shapeless.::[Some[String] with shapeless.record.KeyTag[String("column1"),Some[String]],shapeless.HNil] = Some(value1) :: HNil
q("column1")
// Some[String] = Some(value1)
显然不同之处在于,KeyTag
有一种类型
KeyTag[String("column1"), Some[String]]
和(非工作)其他
KeyTag[k.type,Option[String]] forSome { val k: String }
我感觉问题是字符串k
不是静态知道的,但我不清楚如何解决这个问题。
一般来说,有没有一种方法可以从密钥列表中动态生成可扩展记录?
我担心答案是使用宏,但如果存在另一种解决方案,我会很高兴。
答案 0 :(得分:8)
如果您可以稍微更改Foo
定义以允许它跟踪列键的单例类型(请注意,我已删除了未使用的{},这不是太糟糕{1}}类型参数):
T
然后:
import shapeless._; import syntax.singleton._; import record._
case class Foo[K <: Symbol](column: Witness.Aux[K])
val cols = Foo('column1) :: HNil
val values = Map("column1" -> "value1")
object toRecord extends Poly1 {
implicit def atFoo[K <: Symbol] = at[Foo[K]] { foo =>
field[K](values.get(foo.column.value.name))
}
}
val r = cols.map(toRecord)
请注意,我已将您的字符串键(scala> val value = r('column1)
value: Option[String] = Some(value1)
)更改为符号,因为这是我们在记录中添加的内容。