【问题标题】:case class to shapeless Generic conversion案例类到无形的通用转换
【发布时间】:2020-01-16 11:20:42
【问题描述】:

问题:

我有一个案例类Foo,它可以是任何东西。

我需要一个函数来创建密码查询。

这个新函数的签名应该是

def createQueryString[T](t: T): String = ???

示例:

我有 Foo 假设有两个成员

case class Foo(x: Int, y: String)

我需要将其转换为密码

CREATE (f:Foo { x: "1", y: "Hello" }) RETURN f

如果我将Foo(1, "Hello") 传递给上面提到的函数createQueryString

createQueryString[Foo](Foo(1, "Hello"))

到目前为止我尝试了什么?

我已经尝试使用shapelessGenericAux 来实现这一目标

import shapeless._

case class Foo(x: Int, y: String)

def foo[T, HL <: HList](instance: T)(
  implicit gen: Generic.Aux[T, HL]
): HL = {
  gen.to(instance)
}

val myFoo = foo(Foo(1, "Hello"))
s"""CREATE (f:Foo { x: "${myFoo(0)}", y: "${myFoo(1)}" }) RETURN f"""

有什么方法可以使用这个foo(Foo(1, "Hello")) 在上面提到的createQueryString 内部实现?我想基本上将类型传递给这个函数。有点像

def createQueryString[T](t: T): String = {
  val gen = foo(t) // to get the generic
  s"""CREATE (t: T { x: "${gen(0)}", y: "${gen(1)}" }) RETURN t"""
}

类似的东西。但是这样做我得到以下错误

Error:(77, 22) could not find implicit value for parameter gen: shapeless.Generic.Aux[T,HL]
val gen = foo(t) // to get the generic

问题:

  1. 我在上次使用 Aux 的实现中遗漏了什么?
  2. 如何改进它使其足够通用以作为参数合并到密码查询中?案例类中可以有多个xy

【问题讨论】:

  • @FahadSididiqui 嘿,你有有趣的用例。你见过新类型吗?是 Neo4j (我是其维护者)Scala 驱动程序。在项目中,我们有一个待处理的discussion 关于如何支持这样的事情。你想加入讨论吗?
  • 谢谢@LuisMiguelMejíaSuárez 当然,我会看看我是否可以在你的帖子上分享我的发现。

标签: scala shapeless


【解决方案1】:

您忘记了隐式参数(或上下文边界)。

Generic 不仅可以生成HList,还可以生成Coproduct。这就是为什么如果你松散绑定&lt;: HList 编译器不知道如何将GenericRepr 应用到01

试试

import shapeless.ops.hlist.At
import shapeless.nat._

def foo[T](instance: T)(
  implicit gen: Generic[T]
): gen.Repr = {
  gen.to(instance)
}

def createQueryString[T, L <: HList](t: T)(implicit 
  g: Generic.Aux[T, L],
  at0: At[L, _0], 
  at1: At[L, _1]
): String = {
  val gen = foo(t) // to get the generic
  s"""CREATE (t: T { x: "${gen(0)}", y: "${gen(1)}" }) RETURN t"""
}

如果您需要标签xy,那么您需要LabelledGeneric 而不是Generic

如果您有任意数量的参数,那么您可以将 HList 转换为所需的形式,然后将其折叠为字符串。

{ x: "1", y: "Hello" } 看起来像 JSON。看Circe

【讨论】:

  • 这很好。但是 createQueryString 再次绑定到案例类的 2 个成员。如果我们想在一个函数中处理从 1 到 22 的所有范围怎么办?我正在考虑实施一些减速器。我可以编写一个扩展 Poly2 的减速器。但是,我想我可能需要另一个隐式定义才能使用 foldLeft。
  • @FahadSiddiqui 为什么是 22?案例类、HLists和方法不受22个限制。是的,你可以实现一个reducer。根据需要添加尽可能多的隐式参数(使用 HList 的类型类在这里:shapeless.ops.hlist._)。或者您可以将 HList 转换为普通的字符串列表(无论如何您实际上并没有在 HList 中使用类型)并减少列表。
猜你喜欢
  • 1970-01-01
  • 2014-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多