从 Slick HLIST 获取元素(或将 Slick HLIst 转换为 Shapeless HList) [英] Getting elements from Slick HLIST (or Convert Slick HLIst into Shapeless HList)
问题描述
我使用流畅的代码生成器自动生成了 Scala 代码.我看到一些表格行被实现为 HLists.(但这些是光滑的 HList,而不是普通的无形 HList)
I have auto-generated scala code using slick codegen. I see that some tables Rows are implements as HLists. (but these are slick HList, not the normal shapeless HList)
现在我想要 HList 中的一个特定元素作为 Row 由光滑的查询返回.
Now I want a specific element from the HList returned as a Row by the slick query.
我用谷歌搜索并找到了这个主题
I googled and found this thread
但这不适用于光滑的 HList.它适用于 Shapeless HList
But this does not work for slick HList. it works very well for Shapeless HList
我也试过apply方法
I also tried the apply method
val x : Long = slickHList(2)
val x : Long = slickHList(2)
但这不会编译,因为类型 Any 不符合执行的 Long 类型.我不想做一个 .asInstanceOf
but this doesn't compile because type Any does not conform to exected type of Long. I would hate to do a .asInstanceOf
是否有一种类型安全的方式可以访问光滑的 HList 的元素?
Is there a typesafe way in which I can access the elements of the slick HList?
根据下面的输入,我写了下面的代码
Based on the input below I wrote the code below
package com.abhi
object SlickAndShapeless {
import slick.collection.heterogeneous.{HCons, HList, HNil}
import slick.collection.heterogeneous.syntax.HNil
type MyRow = HCons[Long, HCons[String, HNil]]
val row : MyRow = 1L :: "foo" :: HNil
import HListExtensions._
val hlist = row.asShapeless
val container = new Container(hlist)
val item = container.get(1)
}
class Container[L <: shapeless.HList](list: L) {
import shapeless._
import nat._
import ops.hlist._
def get(n: Nat)(implicit at: At[L, n.N]): at.Out = list[n.N]
}
object HListExtensions {
import slick.collection.heterogeneous.{HNil => SHNil, HList => SHList, HCons}
import shapeless.{::, HList, HNil}
implicit class HListShapelessSlick(val list: HList) extends AnyVal {
def asSlick : SHList = list match {
case HNil => SHNil
case head :: tail => head :: tail.asSlick
}
}
implicit class HListSlickShapeless(val list: SHList) extends AnyVal {
def asShapeless : HList = list match {
case SHNil => HNil
case HCons(head, tail) => head :: tail.asShapeless
}
}
}
上面代码的问题是从val item = container.get(1)
得到的item
的类型是at.Out
而不是我期待的 Long
.
The problem with the code above is that the type of item
obtained from val item = container.get(1)
is at.Out
and not Long
as I was expecting.
build.sbt
libraryDependencies ++= Seq(
"com.typesafe.slick" % "slick_2.12" % "3.2.1",
"com.chuusai" % "shapeless_2.12" % "2.3.2"
)
我还看到两个编译器错误
I also see two compiler errors
Error:(19, 35) Implicit not found: shapeless.Ops.At[shapeless.HList, shapeless.Succ[shapeless._0]]. You requested to access an element at the position shapeless.Succ[shapeless._0], but the HList shapeless.HList is too short.
val item : Long = container.get(1)
Error:(19, 35) not enough arguments for method get: (implicit at: shapeless.ops.hlist.At[shapeless.HList,shapeless.Succ[shapeless._0]])at.Out.
Unspecified value parameter at.
val item : Long = container.get(1)
推荐答案
可以创建扩展方法:
object HListExtensions {
import slick.collection.heterogeneous.{HNil => SHNil, HList => SHList, HCons}
import shapeless.{ ::, HList, HNil }
implicit class HListShapelessSlick(val list:HList) extends AnyVal {
def asSlick:SHList = list match {
case HNil => SHNil
case head :: tail => head :: tail.asSlick
}
}
implicit class HListSlickShapeless(val list:SHList) extends AnyVal {
def asShapeless:HList = list match {
case SHNil => HNil
case HCons(head, tail) => head :: tail.asShapeless
}
}
}
示例:
scala>import HListExtensions._
import HListExtensions._
scala> val x1:HList = 1 :: 2 :: HNil
x1: slick.collection.heterogeneous.HList = 1 :: 2 :: HNil
scala> x1.asShapeless
res1: shapeless.HList = 1 :: 2 :: HNil
scala> x1.asShapeless.asSlick
res2: slick.collection.heterogeneous.HList = 1 :: 2 :: HNil
我希望这会有所帮助.
这是类型级解决方案.
object HListsConvertersTypeLevel {
import shapeless.{::}
sealed trait HConv[From <: heterogeneous.HList, To <: shapeless.HList] {
def convert(list: From): To
}
implicit def buildHConvNil: HConv[heterogeneous.HNil.type, shapeless.HNil] =
new HConv[heterogeneous.HNil.type, shapeless.HNil] {
override def convert(list: heterogeneous.HNil.type): shapeless.HNil = shapeless.HNil
}
implicit def buildHConv[H, T <: heterogeneous.HList, T2 <: shapeless.HList](
implicit conv: HConv[T, T2]): HConv[HCons[H, T], ::[H, T2]] = new HConv[HCons[H, T], ::[H, T2]] {
override def convert(list: HCons[H, T]): ::[H, T2] = {
list.head :: conv.convert(list.tail)
}
}
def toShapeless[A <: heterogeneous.HList, B <: shapeless.HList](list: A)(implicit conv: HConv[A, B]): B = conv.convert(list)
}
示例:
object SlickAndShapeless {
import slick.collection.heterogeneous.{HCons, HNil}
import slick.collection.heterogeneous.syntax.HNil
type MyRow = HCons[Long, HCons[String, HNil]]
val row: MyRow = 1L :: "foo" :: HNil
import HListsConvertersTypeLevel._
val hlist = toShapeless(row)
val item: Long = hlist.head
val item2: String = hlist.tail.head
}
这篇关于从 Slick HLIST 获取元素(或将 Slick HLIst 转换为 Shapeless HList)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!