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

Gab*_*lla 8 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")
Run Code Online (Sandbox Code Playgroud)

如果我尝试手动定义记录,一切都按预期工作

 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)
Run Code Online (Sandbox Code Playgroud)

显然,区别在于在一种情况下KeyTag具有类型

KeyTag[String("column1"), Some[String]]
Run Code Online (Sandbox Code Playgroud)

在(非工作)其他

KeyTag[k.type,Option[String]] forSome { val k: String }
Run Code Online (Sandbox Code Playgroud)

我觉得问题是字符串k不是静态知道,但我不知道如何解决这个问题.一般来说,有没有一种方法可以从密钥列表中动态生成可扩展记录?

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

Tra*_*own 8

如果您可以Foo稍微更改定义以允许它跟踪列键的单例类型(请注意我已删除未使用的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)
Run Code Online (Sandbox Code Playgroud)

然后:

scala> val value = r('column1)
value: Option[String] = Some(value1)
Run Code Online (Sandbox Code Playgroud)

请注意,我已将您的字符串键("column1")更改为符号,因为这是我们放入记录的内容.