标记案例 class 上的 LabelledGeneric 实例生成在 shapeless 中产生错误
LabelledGeneric instance generation on a tagged case class yields me an error in shapeless
我试图从来自另一个 HList(确切地说是另一个 LabelledGeneric)的标记类型中获取一个 LabelledGeneric 实例,但是编译器给我一个错误,说它找不到隐式。
准确的错误是(启用-x-log-implicits):
shapeless.this.DefaultSymbolicLabelling.mkDefaultSymbolicLabelling is not a valid implicit value for shapeless.DefaultSymbolicLabelling.Aux[Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner],K] because:
hasMatchingSymbol reported error: Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner] is not case class like or the root of a sealed family of types
这是片段:
case class Inner(a: Int)
case class Outer(b: Int, c: Inner)
val gen = LabelledGeneric[Outer]
val inner = Inner(1)
val outer = Outer(2, inner)
def getGen[A, L](x: A)(implicit gen: LabelledGeneric.Aux[A, L]) = gen
val hOuter = gen.to(outer)
getGen(hOuter.at(1))
我是不是漏掉了什么明显的东西?
谢谢。
编辑:
我添加了案例的定义类。我也在使用 scala 2.11.8 和 shapeless 2.3.0
LabelledGeneric[Outer]
将 Outer
类型的值放入无形记录中。这些是 HList
个字段,每个字段都是一个标记有其 "label" 的值 ... 与案例 class 中的字段名称相对应的单例类型。类型 T
的标记值是类型 T
的子类型,但这两种类型并不相同。通常这绝对没问题。
在您的场景中,您使用的是FieldType['c.type, Inner]
类型的字段hOuter.at(1)
。这是一个类型别名,扩展为以下内容,
Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
然后您请求与该类型对应的 LabelledGeneric
实例。不幸的是,虽然 Inner
有一个 LabelledGeneric
实例,但 FieldType['c.type, Inner]
没有实例,因为正如编译器错误消息所说(扩展类型),
Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
is not case class like or the root of a sealed family of types
如果您实际上没有将标签用于任何事情,那么最简单的解决方法是在整个过程中使用 Generic
而不是 LabelledGeneric
,或者至少在 [=26] 的定义中=].
如果您正在使用标签,那么解决您的问题的方法是将它们从字段中删除。做到这一点的最简单的方法,将在这里工作但不会概括,是依靠 Inner
作为 FieldType['c.type, Inner]
的子类型并使用类型归属,
getGen(hOuter.at(1): Inner)
这意味着 getGen
的类型参数 A
将被推断为 Inner
并且 LabelledGeneric[A]
的隐式查找将成功。
更通用的解决方案是使用 shapeless 的 Values
类型 class,它采用无形记录并剥离其每个元素的标签,从而产生一个 HList
,仅包含值。
我试图从来自另一个 HList(确切地说是另一个 LabelledGeneric)的标记类型中获取一个 LabelledGeneric 实例,但是编译器给我一个错误,说它找不到隐式。
准确的错误是(启用-x-log-implicits):
shapeless.this.DefaultSymbolicLabelling.mkDefaultSymbolicLabelling is not a valid implicit value for shapeless.DefaultSymbolicLabelling.Aux[Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner],K] because:
hasMatchingSymbol reported error: Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner] is not case class like or the root of a sealed family of types
这是片段:
case class Inner(a: Int)
case class Outer(b: Int, c: Inner)
val gen = LabelledGeneric[Outer]
val inner = Inner(1)
val outer = Outer(2, inner)
def getGen[A, L](x: A)(implicit gen: LabelledGeneric.Aux[A, L]) = gen
val hOuter = gen.to(outer)
getGen(hOuter.at(1))
我是不是漏掉了什么明显的东西?
谢谢。
编辑:
我添加了案例的定义类。我也在使用 scala 2.11.8 和 shapeless 2.3.0
LabelledGeneric[Outer]
将 Outer
类型的值放入无形记录中。这些是 HList
个字段,每个字段都是一个标记有其 "label" 的值 ... 与案例 class 中的字段名称相对应的单例类型。类型 T
的标记值是类型 T
的子类型,但这两种类型并不相同。通常这绝对没问题。
在您的场景中,您使用的是FieldType['c.type, Inner]
类型的字段hOuter.at(1)
。这是一个类型别名,扩展为以下内容,
Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
然后您请求与该类型对应的 LabelledGeneric
实例。不幸的是,虽然 Inner
有一个 LabelledGeneric
实例,但 FieldType['c.type, Inner]
没有实例,因为正如编译器错误消息所说(扩展类型),
Inner with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("c")],Inner]
is not case class like or the root of a sealed family of types
如果您实际上没有将标签用于任何事情,那么最简单的解决方法是在整个过程中使用 Generic
而不是 LabelledGeneric
,或者至少在 [=26] 的定义中=].
如果您正在使用标签,那么解决您的问题的方法是将它们从字段中删除。做到这一点的最简单的方法,将在这里工作但不会概括,是依靠 Inner
作为 FieldType['c.type, Inner]
的子类型并使用类型归属,
getGen(hOuter.at(1): Inner)
这意味着 getGen
的类型参数 A
将被推断为 Inner
并且 LabelledGeneric[A]
的隐式查找将成功。
更通用的解决方案是使用 shapeless 的 Values
类型 class,它采用无形记录并剥离其每个元素的标签,从而产生一个 HList
,仅包含值。