我试图使用无形的hlist来构建内省的URL模板,但是我在浏览HList时遇到了麻烦。以下不编译:
import shapeless.{::, HList, HNil}
import shapeless.LUBConstraint._
import shapeless.ops.hlist.ToTraversable._
import scala.util.Try
import shapeless.ops.hlist._
object Path {
def /(s: String) = Path(PathLiteral(s) :: HNil)
def param[T](name: String) = PathParameter(name)
}
sealed trait PathSegment[+T]
case class PathLiteral(value: String) extends PathSegment[String]
case class PathParameter[+T](name: String) extends PathSegment[T]
case class Path[L <: HList : <<:[PathSegment[_]]#λ](segments: L)
(implicit ev: ToList[L, PathSegment[_]])
{
def /(literal: String) = Path(PathLiteral(literal) :: segments)
def /[T](param: PathParameter[T]) = Path(param :: segments)
override def toString: String = s"Path(${segments.toList.reverse})"
}
object Test extends App {
import Path.param
val myPath = Path / "v1" / "pets" / param[String]("name") / "pictures"
println(myPath)
}
在我看来,ToTraversable._
导入涵盖了HNil案例以及具有HList尾部和具有相同最小上界的新头部的情况。显然,我要么错过了导入,要么误解了一切。
我不确定是否将类中的证据缓存为隐式参数是犹太教的;我这样做是因为
答案 0 :(得分:0)
这不起作用的原因是隐含的,可以证明:
给出 ToList[PathLiteral :: L, PathSegment[_]]
ToList[L, PathSegment[L]]
L <: HList
是来自hlists.scala的隐式def的类型签名:
implicit def hlistToTraversable[H1, H2, T <: HList, LubT, Lub0, M[_]]
(implicit
tttvs : Aux[H2 :: T, M, LubT],
u : Lub[H1, LubT, Lub0],
cbf : CanBuildFrom[M[Lub0], Lub0, M[Lub0]]) : Aux[H1 :: H2 :: T, M, Lub0]
实际上需要知道列表头部的类型以及新项目(H1
和H2
),因此无法根据我班级内的可用内容构建。< / p>
在HList旁边手动构建列表
case class Path[L <: HList](segments: L, segmentsList: List[PathSegment[_]]) {
def /(literal: String) = Path(PathLiteral(literal) :: segments, PathLiteral(literal) :: segmentsList)
def /[T](param: PathParameter[T]) = Path(param :: segments, param :: segmentsList)
override def toString: String = s"Path(${segmentsList.reverse})"
}
将隐式参数推送到Path的方法
def printPath[L <: HList](path: Path[L])
(implicit ev: ToList[L, PathSegment[_]]) =
path.segments.toList.reverse.collect {
case PathLiteral(value) => URLEncoder.encode(value, "UTF-8")
case PathParameter(name) => s"<$name>"
}.mkString("/")
printPath(Path / "v1" / "pets" / param[String]("name") / "pictures")
// v1/pets/<name>/pictures