假设我想遍历用例类的通用表示,如所述
我定义了一些类型类来描述字段:
trait Described[X] extends (X => String)
object Described{
def apply[X](x: X)(implicit desc: Described[X]) = desc(x)
}
定义了一些实例:
implicit object DoubleDescribed extends Described[Double]{
def apply(x: Double) = x.formatted("%01.3f")
}
普通用户:
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
object DescrFolder extends Poly2{
implicit def field[X, S <: Symbol](implicit desc: Described[X],
witness: Witness.Aux[S]):
Case.Aux[Seq[String], FieldType[S, X], Seq[String]] =
at[Seq[String], FieldType[S, X]](
(descrs, value) => descrs :+ f"${witness.value.name}: ${desc(value)}")
}
def describe[T <: Product, Repr <: HList](struct: T)
(implicit lgen: LabelledGeneric.Aux[T,Repr],
folder: LeftFolder.Aux[Repr, Seq[String], DescrFolder.type, Seq[String]]
): String = {
val repr = lgen.to(struct)
val descrs = folder(repr,Vector())
descrs.mkString(struct.productPrefix + "{", ",", "}")
}
所以现在我可以写了
case class Point(x: Double, y: Double, z: Double)
describe(Point(1,2,3.0))
并获得
res1:字符串=点{x:1000,y:2000,z:3000}
现在我想使用shapeless
标签定义一些字段元数据:
import tag._
trait Invisible
val invisible = tag[Invisible]
implicit def invisibleDescribed[X](implicit desc: Described[X])
: Described[X @@ Invisible] =
new Described[X @@ Invisible]{
def apply(x: X @@ Invisible) = desc(x: X) + "[invisible]"
}
因此Described(invisible(0.5))
现在成功地产生
res2:字符串=0500[不可见]
但随着的重新定义
case class Point(x: Double, y: Double, z: Double @@ Invisible)
describe(Point(1,2,invisible(3.0)))
产生编译错误:
错误:类型的发散隐式展开
LeftFolder.Aux[this.Out,Seq[String],DescrFolder.type,Seq[String]]
从类中的方法invisibleDescribed
开始。。。
我认为类型X with Tag[Y] with KeyTag[K,X]
没有识别为FieldType[S, X]
,但无法猜测如何修复它
在这种情况下,如何定义合适的LeftFolder
?
您的问题根本不涉及shapeless
。它实际上可以简化为:
trait Described[T]
trait Invisible
implicit val doubleDescribed: Described[Double] = ???
implicit def invisibleDescribed[T](
implicit desc: Described[T]
): Described[T with Invisible] = ???
implicitly[Described[Double with Invisible]]
Double @@ Invisible
可以"表示"为Double with Invisible
。注意Double with Invisible <: Double
。
当编译器试图获得隐式Described[Double with Invisible]
时,它会正确地抱怨隐式扩展的发散:doubleDescribed
和invisibleDescribed
。
回到您的原始代码,一个简单的修复方法可以是将invisibleDescribed
重写为:
implicit def invisibleDescribed[X, I <: X @@ Invisible](
implicit desc: Described[X]
): Described[I] = new Described[I]{
def apply(x: I) = desc(x: X) + "[invisible]"
}