在无形2.0中动态创建可扩展记录

时间:2014-08-13 10:51:56

标签: scala shapeless

我需要生成一个可扩展的记录,给出一个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不是静态知道的,但我不清楚如何解决这个问题。 一般来说,有没有一种方法可以从密钥列表中动态生成可扩展记录?

我担心答案是使用宏,但如果存在另一种解决方案,我会很高兴。

1 个答案:

答案 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) )更改为符号,因为这是我们在记录中添加的内容。