scala - 无形。如何按键过滤 LabelledGeneric 记录?
问题描述
我有下一段要用于创建类型类实例的代码:
def productsLogShow[HK <: HList, T, H <: HList, K](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], keys: Keys.Aux[H, K]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
// ...
//filter somehow record and get a record without
// keys which are in 'hideFieldsWithKeys'
// ...
}
}
那么,如何过滤记录并使用正确的hideFieldsWithKeys
参数类型?
更新:应该根据 Dmitro 的回答工作的完整代码片段
object Main extends App {
trait LogShow[T] {
def show(value: T): String
}
object LogShow {
def apply[T: LogShow]: LogShow[T] = implicitly[LogShow[T]]
def create[T](f: T => String): LogShow[T] = new LogShow[T] {
override def show(value: T): String = f(value)
}
}
import LogShow.create
implicit val StringShow: LogShow[String] = create(identity)
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.Remover
import scala.reflect.ClassTag
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)
(implicit
ct: ClassTag[T],
lg: LabelledGeneric.Aux[T, H],
rem: RemoverAll.Aux[H, HK, H1],
lsh: LogShow[H1]): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val clearedRecord = rem(record, hideFieldsWithKeys)
s"${ct.runtimeClass.getSimpleName}:\n${lsh.show(clearedRecord)}"
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] {type Out = Out0}
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicit def hconsLogShow[K <: Symbol, H, T <: HList](implicit
wt: Witness.Aux[K],
lshHead: LogShow[H],
lshTail: LogShow[T]): LogShow[FieldType[K, H] :: T] =
LogShow.create { value =>
s"${wt.value.name}: ${lshHead.show(value.head)}\n${lshTail.show(value.tail)}"
}
implicit val hnilLogShow: LogShow[HNil] = LogShow.create(_ => "")
//test
case class Address(country: String, street: String)
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
//could not find implicit value for parameter lg: shapeless.LabelledGeneric.Aux[T,H]
//[error] implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
println(implicitly[LogShow[Address]].show(Address("Ukraine", "Gorkogo")))
}
解决方案
尝试
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.{Keys, Remover}
import shapeless.{::, DepFn2, HList, HNil, LabelledGeneric, Poly2, Witness}
import shapeless.record.Record
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], /*keys: Keys.Aux[H, K]*/ rem: RemoverAll.Aux[H, HK, H1]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val record1 = rem(record, hideFieldsWithKeys)
???
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] { type Out = Out0 }
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicitly[RemoverAll.Aux[Record.`'i -> Int, 's -> String, 'b -> Boolean`.T, Witness.`'s`.T :: Witness.`'i`.T :: HNil, Record.`'b -> Boolean`.T]]
换行
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
和
import shapeless.syntax.singleton._
implicit val inst: LogShow[Address] = productsLogShow('country.narrow :: HNil)
'country
有类型Symbol
而不是必要的单例类型Witness.`'country`.T
。
推荐阅读
- tableau-api - 如何在 Tableau 仪表板上创建响应式布局?
- netsuite - Netsuite 打印个人声明
- java - Axon - SubscribingEvent 与 TrackingEvent 处理器
- spring-boot - 有没有办法在使用 Spock 框架时使用 @MockBean 注释
- java - 如何将用户信息从数据库添加到“inMemoryAuthentication”
- python - 在“............”之前提取字符串
- ruby-on-rails - 查询以通过关联从 has_many 检索对象
- node.js - 在我的服务器上的 Docker 容器中运行 Node-Red - 在哪里存储数据文件 (csv)?
- android - 在布局xml中禁用Android EditText时如何将文本样式显示为粗体?
- spring-integration - 配置 Spring 集成。错误处理任务执行器