我正在努力以类型安全的方式开展这项工作:
val rows = db.select( ID_COLUMN, STR("name"), INT("count") ). from("tablename") ......
for ( (id, name, count) <- rows ) {
//some code to use the individual values
}
到目前为止,我还没有找到另一种使这种类型安全的方法除了无形之外。
我确实知道光滑和其他ORM,所以请不要发送给我。
HList似乎是接近传递异构数据集的方法,并返回具有特定类型的值列表。
我试着这样做:
trait ColDef [X] {
def colName
def valalue (m:Map[String, Object]):X
}
object XS extends ColDef[String]{
def colName = "s"
def value (m:Map[String, Object]) = m("s").asInstanceOf[String]
}
object XI extends ColDef[Integer]{
def colName = "i"
def value (m:Map[String, Object]) = m("i").asInstanceOf[Integer]
}
val xhl = XS::XI::HNil
val data:Map[String,Object] = Map(("s" ->"asdf"), ("i" -> new Integer(5)))
object p1 extends Poly1 {
implicit def getValue[T, S <% ColDef[T]] = at[S] (coldef => coldef.value(data) )
}
val res = xhl map p1
val (s, i) = res.tupled //this works, giving s:String, and i:Integer
//but following does not compile
def nextstep(hl : HList, data:Map[String,Object]) = {
hl map p1
}
重申必要条件:
HList / Shapeless可能是解决问题的候选者,但不是本练习的目标。我的目标是让函数的返回类型对应于传入的变量类型和参数数量。
如果我的小实用程序的用户不需要知道HList,那将是理想的,但这不是真正的要求。
关键部分是使结果的类型与params的类型匹配:
val param1 = new Conf[String]
val param2 = new Conf[Integer]
... etc ....
val res = function(param1, param2, param3)
更准确地说,上面的参数有效载荷类型,因此res的类型是T(String,Integer,....)。
让我补充一点澄清。我想为任意arity创建一个方法,并避免为每个参数计数创建一个函数。如果我对22种方法没问题,它看起来像这样:
def f[A](a:ColDef[A]):(A)
def f[A,B](a:ColDef[A], b:ColDef[B]):(A,B)
def f[A,B,C](a:ColDef[A], b:ColDef[B],c:ColDef[C]):(A,B,C)
..... and so on
然后我不需要无形或HList,因为所有可能的元组都会被明确定义。
实际上看看这3个签名 - 制作它们22会花费一些时间,但会避免无形依赖,他们的实现也会是单行。也许我应该花30分钟手动(或用一个小脚本)。
答案 0 :(得分:1)
您只需要对nextstep
的定义进行一些小的调整:
def nextstep[L <: HList](hl: L, data: Map[String, Object])(implicit mapper: Mapper[p1.type, L]): mapper.Out = {
hl map p1
}
我将HList L
的确切类型设为类型参数,我需要map
所需的隐式(请参阅map
的定义)。
然后您(或您的用户)可以直接致电
nextstep(XS :: XI :: HNil, data)
他们将获得String :: Integer :: HNil
作为返回类型。它适用于任何ColDef[...]
的HList(返回结果的HList)。
为了让它返回一个元组而不是一个HList,你可以这样定义它:
import shapeless.ops.hlist.{Tupler, Mapper}
def nextstep[L <: HList, OutL <: HList, Out](hl: L, data: Map[String, Object])(implicit mapper: Mapper.Aux[p1.type, L, OutL], tupler: Tupler.Aux[OutL, Out]): Out = {
tupler(hl map p1)
}
nextstep(XS :: XI :: HNil, data)
将返回(String, Integer)
,nextstep
将返回正常情况下正确输入的元组。
接受ColDef
元组作为输入并返回元组作为输出的最后一步如下:
def nextstep[P, L <: HList, OutL <: HList, Out](c: P, data: Map[String, Object])(implicit gen: Generic.Aux[P, L], mapper: Mapper.Aux[p1.type, L, OutL], tupler: Tupler.Aux[OutL, Out]): Out = {
tupler(gen.to(c) map p1)
}
这里的逻辑与shapeless.syntax.std.TupleOps
中定义的函数非常相似:将元组转换为HList,处理HList,将输出转换为元组。