问题
Assuming if I have the following Record typed data, and a hlist of keys:
val rr = ("a" ->> 1) ::
("b" -> "s") ::
("c" -> 3) ::
HNil
val hh = "c" :: "b" :: HNil
And I want to extract values in rr
for each key in hh
, then combine them into a type level object, eventually yielding:
(3: Int) :: ("s": String) :: HNil
How this can be achieved with least amount of code? I could obviously write a inductively-summoned implicit function but it seems to be overkill
回答1:
Firstly, you have typos. ->>
should be instead of ->
.
Secondly, val hh = "c" :: "b" :: HNil
doesn't have type "c" :: "b" :: HNil
, it has type String :: String :: HNil
instead (so you're loosing compile-time information about keys). If you want hh
to have type "c" :: "b" :: HNil
(so that values with such keys can be extracted from rr
) then you should use .narrow
type hht = "c" :: "b" :: HNil
val hh: hht = "c".narrow :: "b".narrow :: HNil
Thirdly, if you want to extract a value from a record by a key you should use type class shapeless.ops.record.Selector
. If you want to extract several values by several keys you should use type class shapeless.ops.record.SelectAll
. There is extension method get
/apply
defined via Selector
in shapeless.record._
but I can't find the one defined via SelectAll
so you can define it yourself similarly to get
/apply
implicit class RecordOps[L <: HList](val l : L) {
def getAll[K <: HList](k: K)(implicit selector: SelectAll[L, K]): selector.Out =
selector(l)
def getAllByType[K <: HList](implicit selector: SelectAll[L, K]): selector.Out =
selector(l)
}
rr.getAll(hh) // 3 :: s :: HNil
rr.getAllByType[hht] // 3 :: s :: HNil
来源:https://stackoverflow.com/questions/66020239/can-shapeless-record-type-be-used-as-a-poly1