从 HList 中检索元素的函数(同时保留其类型)

Function that retrieves element from HList (while preserving its type)

我有这种类型,它将通过 shapeless 生成:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

基本上我有一堆扩展特征的案例对象,所以我设法创建了一个方法,它给我所有案例对象的实例作为一个 HList

然后使用 import shapeless.ops.hlist.Lastinit 我写了一个方法来检索 HList 中的一个节点,如果该值等于字符串 "student":

def getLast(hl:hlistt) = {
  val last0=Last[hlistt]
  val la=last0(hl)

  if (la.value == "student") la
  else init(hl)
}

问题是,如果我调用此方法,我将无法从 HList 中获取正确的节点类型。

getLast(STUDENT :: AUTO_LOANS :: HNil)

该方法有效并且 returns 节点但类型已关闭:

Product with Serializable = STUDENT :: HNil

我需要一些 Witness/Aux 隐含到 return 正确的类型吗?

我不太确定你想做什么。给定:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

Last[hlistt] 将解析为 AUTO_LOANS.type(您的 true if 分支) 而 init 将解析为 STUDENT :: HNil (如果分支为 false)

这些类型的 LUB(最小上限)将为 Product with Serializable,这就是您看到的原因。

如果您想检查 hlist 成员的运行时 属性,您必须通过使用适当的机制派生适当的类型边界和结果类型。在这种情况下,shapeless 已经给出了。

https://scalafiddle.io/sf/fdtn3cz/0

这是你想要的吗?

编辑: 我也刚读

I have this type which will be generated dynamically:

"dynamically" 到底是什么意思?因为除非您可以指定一些编译时属性,否则 shapeless 可能不是您正在寻找的解决方案。

laAUTO_LOANS.type类型,init(hl)STUDENT.type :: HNil类型,所以

if (la.value == "student") la
else init(hl)

类型为 Any(或 Product with Serializable)。

如果您想 return 来自不同分支的不同类型的值,您需要 Poly

import shapeless.{Poly1, Witness}

object myPoly extends Poly1 {
  implicit def studentCase: Case.Aux[Witness.`"student"`.T, STUDENT.type] = 
    at(_ => STUDENT)
  implicit def autoLoansCase: Case.Aux[Witness.`"auto-loans"`.T, AUTO_LOANS.type] = 
    at(_ => AUTO_LOANS)
}

import shapeless.syntax.singleton._
println(
  myPoly("student".narrow)
) // STUDENT

println(
  myPoly("auto-loans".narrow)
) // AUTO_LOANS

// println(
//   myPoly("abc".narrow)
// )  // doesn't compile

如果字符串在编译时已知,则此方法有效。