问题描述
我目前有以下(不是类型安全的)api,我正在尝试以类型安全的方式进行重新设计:
import cats.instances.list._
import cats.Syntax.functorFilter._
sealed trait EnumType
case object A extends EnumType
case object B extends EnumType
case object C extends EnumType
sealed abstract class TypeInfo[T <: EnumType](val enumType: T)
case class Ainfo() extends TypeInfo(A)
case class Ainfo2() extends TypeInfo(A)
case class Binfo() extends TypeInfo(B)
case class Cinfo() extends TypeInfo(C)
//This is the function implemented in a not typesafe way
def filterByEnumType[T <: EnumType: classtag](lst: List[TypeInfo[_]]): List[TypeInfo[T]] = {
lst mapFilter { info =>
info.enumType match {
case _: T => Some(info.asInstanceOf[TypeInfo[T]]) //not type safe
case _ => None
}
}
}
filterByEnumType[A.type](List(Ainfo(),Binfo(),Ainfo2(),Cinfo())) //List(Ainfo(),Ainfo2())
有没有一种方法可以安全地实现它?键入成员是否对此类任务有用,或者可能shapeless
可以用于该任务?
解决方法
我想出了两种不相关的相关方法。我不确定两者是否都能完全满足您的需求,因为它们取决于提前知道列表中所有类型的元素。
假设您拥有这些东西:
import shapeless._
import shapeless.ops.hlist._
type HType = TypeInfo[A.type] :: TypeInfo[B.type] :: TypeInfo[A.type] :: TypeInfo[C.type] :: HNil
val hlist: HType = Ainfo() :: Binfo() :: Ainfo2() :: Cinfo() :: HNil
您可以直接在HList
上使用过滤器:
hlist.filter[TypeInfo[A.type]] // Ainfo() :: Ainfo2() :: HNil
如果要避免在过滤器调用中显式指定TypeInfo
,则可以修改过滤器功能(但现在需要提供HList类型-可以使用代理类来解决此问题):
def filterByEnumType[T <: EnumType,L <: HList](
list: L
)(implicit filter: Filter[L,TypeInfo[T]]): filter.Out = {
filter.apply(list)
}
filterByEnumType[A.type,HType](hlist) // Ainfo() :: Ainfo2() :: HNil