scala – Shapeless在测试中没有发现implicits,但可以在REPL中找
我有一个类似于下面的案例类:
case class Color(name: String,red: Int,green: Int,blue: Int) 我正在使用Scala 2.11.8的Shapeless 2.3.1.我发现我的测试和REPL在查找LabelledGeneric [Color]的隐含值方面有不同的行为. (我实际上是在尝试自动派生一些其他的类型类,但我也是因为这个也是空的) 内部测试 package foo import shapeless._ import org.specs2.mutable._ case class Color(name: String,blue: Int) object CustomProtocol { implicit val colorLabel: LabelledGeneric[Color] = LabelledGeneric[Color] } class GenericFormatsSpec extends Specification { val color = Color("CadetBlue",95,158,160) "The case class example" should { "behave as expected" in { import CustomProtocol._ assert(colorLabel != null,"colorLabel is null") 1 mustEqual 1 } } } 此测试失败,因为colorLabel为null.为什么? REPL 从REPL中,我可以找到LabelledGeneric [Color]: scala> case class Color(name: String,blue: Int) defined class Color scala> import shapeless._ import shapeless._ scala> LabelledGeneric[Color] res0: shapeless.LabelledGeneric[Color]{type Repr = shapeless.::[String with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("name")],String],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("red")],Int],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("green")],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("blue")],shapeless.HNil]]]]} = shapeless.LabelledGeneric$$anon$1@755f11d9 解决方法
实际上,您看到的null是隐式定义语义的一个令人惊讶的结果,有或没有显式注释类型. LabelledGeneric [Color]定义右侧的表达式是对象LabelledGeneric上的apply方法的调用,类型参数为Color,它本身需要一个类型为LabelledGeneric [Color]的隐式参数.隐式查找规则意味着具有最高优先级的相应的范围内隐式定义是当前正在定义的隐式val colorLabel,即.我们有一个循环,最终获得默认的null初始化程序的值.如果OTOH没有关闭类型注释,则colorLabel不在范围内,您将获得预期的结果.这是不幸的,因为正如您正确地观察到的那样,我们应该尽可能明确地注释隐式定义.
shapeless的cachedImplicit提供了解决这个问题的机制,但在描述它之前,我需要指出一个额外的复杂性. LabelledGeneric [Color]类型不是colorLabel的正确类型. LabelledGeneric有一个类型成员Repr,它是你要实例化LabelledGeneric的类型的表示类型,并且通过注释定义,你明确地放弃了LabelledGeneric [Color]的细化,包括它.结果值将是无用的,因为其类型不够精确.使用正确的类型注释隐式定义,使用显式细化或使用等效的Aux很困难,因为表示类型很难明确写出, object CustomProtocol { implicit val colorLabel: LabelledGeneric.Aux[Color,???] = ... } 同时解决这两个问题是一个两步过程, >使用完全细化的类型获取LabelledGeneric实例. 最终看起来像这样, object CustomProtocol { val gen0 = cachedImplicit[LabelledGeneric[Color]] implicit val colorLabel: LabelledGeneric.Aux[Color,gen0.Repr] = gen0 } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |