import shapeless._
import syntax.singleton._
val book = ("author" ->> "Benjamin Pierce") ::
("title" ->> "Types and Programming Languages") ::
("id" ->> "foo") ::
("price" ->> "bar") ::
HNil
我想找到映射到 "foo"
的字段键(在本例中为 "id"
)并检索它,输入为 4 单例的联积字符串。
我该怎么做?
最佳答案
我建议使用自定义类型类以不同方式(并且更通用)来执行此操作:
import shapeless._
import shapeless.labelled.FieldType
trait RecSearch[R <: HList, A] {
type Keys <: Coproduct
def find(r: R, a: A): Option[Keys]
}
object RecSearch extends LowPriorityRecSearchInstances {
implicit def hnilRecSearch[A]: Aux[HNil, A, CNil] =
new RecSearch[HNil, A] {
type Keys = CNil
def find(r: HNil, v: A): Option[CNil] = None
}
implicit def cconsRecSearch1[K, V, T <: HList](implicit
trs: RecSearch[T, V],
wit: Witness.Aux[K]
): Aux[FieldType[K, V] :: T, V, K :+: trs.Keys] =
new RecSearch[FieldType[K, V] :: T, V] {
type Keys = K :+: trs.Keys
def find(r: FieldType[K, V] :: T, a: V): Option[K :+: trs.Keys] =
if (r.head == a)
Some(Coproduct[K :+: trs.Keys](wit.value))
else trs.find(r.tail, a).map(_.extendLeft[K])
}
}
trait LowPriorityRecSearchInstances {
type Aux[R <: HList, A, K <: Coproduct] = RecSearch[R, A] { type Keys = K }
implicit def cconsRecSearch0[A, K, V, T <: HList](implicit
trs: RecSearch[T, A]
): Aux[FieldType[K, V] :: T, A, K :+: trs.Keys] =
new RecSearch[FieldType[K, V] :: T, A] {
type Keys = K :+: trs.Keys
def find(r: FieldType[K, V] :: T, a: A): Option[K :+: trs.Keys] =
trs.find(r.tail, a).map(_.extendLeft[K])
}
}
然后:
def search[R <: HList, A](r: R)(a: A)(implicit rs: RecSearch[R, A]): Option[rs.Keys] =
rs.find(r, a)
最后:
import syntax.singleton._
val book = ("author" ->> "Benjamin Pierce") ::
("title" ->> "Types and Programming Languages") ::
("id" ->> "foo") ::
("price" ->> "bar") ::
HNil
search(book)("foo")
这将向您显示(非常详细的)副产品类型和正确的值:
Some(Inr(Inr(Inl(id))))
你的版本不适合我编译,所以我不能真正比较两者,但 95% 的时间我开始使用 Poly
我最终切换到一个类型类一些点。
关于scala - 获取字段键作为副产品,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36943693/