[英]Shapeless HList implicit resolution - diverging implicit expansion
This is really bugging me. 这真是困扰我。 I am getting a
diverging implicit expansion for type Meta[Field2 :: HNil]
error which I try and compile the following: 我收到
diverging implicit expansion for type Meta[Field2 :: HNil]
错误的diverging implicit expansion for type Meta[Field2 :: HNil]
但我尝试编译以下内容:
case class Field() extends StaticAnnotation
case class Group() extends StaticAnnotation
case class Message() extends StaticAnnotation
@Field case class Field1(value: String)
@Field case class Field2(value: String)
@Field case class Field3(value: String)
@Group case class Group1(field1: Field1, field2: Field2)
@Message case class Message1(field3: Field3, group1: Group1)
trait Meta[T]
object Meta {
implicit val hNil: Meta[HNil] = new Meta[HNil] {}
implicit def field[TField](implicit a: Annotation[Field, TField]): Meta[TField] = new Meta[TField] {}
implicit def hcons[Head, Tail <: HList](implicit h: Meta[Head], t: Meta[Tail]) : Meta[H :: T] = new Meta[H :: T] {}
implicit def group[TGroup, ParamList <: HList](implicit a: Annotation[Group, TGroup], g: Generic.Aux[TGroup, ParamList], p: Meta[ParamList]): Meta[TGroup] = new Meta[TGroup] {}
implicit def message[TMessage, ParamList <: HList](implicit a: Annotation[Message, TMessage], g: Generic.Aux[TMessage, ParamList], p: Meta[ParamList]): Meta[TMessage] = new Meta[TMessage] {}
}
object TestApp extends App {
// throws compile exception here...
implicitly[Meta[Message1]]
}
Consider the process of expanding Meta[Message1]
: 考虑扩展
Meta[Message1]
:
Meta[Message1]
with message
the compiler needs Meta[Field3 :: Group1 :: HNil]
message
扩展Meta[Message1]
时,编译器需要Meta[Field3 :: Group1 :: HNil]
Meta[Group1]
with group
it needs Meta[Field1 :: Field2 :: HNil]
group
扩展Meta[Group1]
时,需要Meta[Field1 :: Field2 :: HNil]
The compiler sees, that in this branch it has already expanded type constructor ::
of at least the same complexity (ie, with the same number of elements in the HList
). 编译器看到,在该分支中,它已经扩展了类型构造器
::
,其复杂度至少相同(即, HList
的元素数相同)。 So it assumes, that this expansion branch results in an infinite loop, and reports implicit divergence. 因此,它假定此扩展分支会导致无限循环,并报告隐式发散。
To prevent this behaviour you can use shapeless.Lazy
. 要防止此行为,可以使用
shapeless.Lazy
。 From the documentation: 从文档中:
Wraps a lazily computed value.
包装延迟计算的值。 Also circumvents cycles during implicit search, or wrong implicit divergences as illustrated below, and holds the corresponding implicit value lazily.
还可以避开隐式搜索过程中的循环,或错误的隐式发散度,如下所示,并懒惰地保存相应的隐式值。
So to fix this problem you can wrap in Lazy
the expansion of Head
in hcons
: 因此,要解决此问题,您可以在
hcons
Head
的扩展包装在Lazy
中:
implicit def hcons[Head, Tail <: HList](implicit
h: Lazy[Meta[Head]],
t: Meta[Tail]
): Meta[Head :: Tail] =
new Meta[Head :: Tail] {}
Usually you should wrap in Lazy
the expansions of heads in HList
and Coproduct
rules, and also the expansion of Repr
in Generic
rules. 通常你应该在包装
Lazy
的头扩展中HList
和Coproduct
规则,也扩大Repr
的Generic
规则。 The latter is not necessary here, I think, because you'll necessary go through hcons
rule, that already has Lazy
, to get from one Group
or Message
to another). 我认为,后者在这里不是必需的,因为您将需要通过
hcons
规则(已经具有Lazy
,以从一个Group
或Message
传递到另一个)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.