Scala中如何测试某类型是否为type class的成员?
可以通过隐式解析优先级兜底的方式实现编译时检测type class实例是否存在,无需修改现有方法签名。
基础实现
你可以先定义一个用于检测Foo类型类实例是否存在的辅助标记:
trait Foo[A] trait Marshaller[Node] { def isFoo(n: Node): Boolean } // 辅助检测工具:标记类型A是否存在Foo类型类实例 trait IsFoo[A] { def value: Boolean } object IsFoo extends LowPriorityIsFoo { // 高优先级:当A存在Foo实例时返回true implicit def exists[A: Foo]: IsFoo[A] = new IsFoo[A] { val value = true } } trait LowPriorityIsFoo { // 低优先级兜底:不存在时返回false implicit def notExists[A]: IsFoo[A] = new IsFoo[A] { val value = false } }
之后在你的实现类中引入该隐式即可:
class MyMarshaller[Node](implicit isFooInst: IsFoo[Node]) extends Marshaller[Node] { override def isFoo(n: Node): Boolean = isFooInst.value }
如果你的Scala版本在2.13及以上,还可以用更简洁的默认隐式参数写法:
class MyMarshaller[Node] extends Marshaller[Node] { private val hasFoo: Boolean = { implicit def defaultFoo: Foo[Node] = null implicitly[Foo[Node]] != null } override def isFoo(n: Node): Boolean = hasFoo }
注意:如果项目中存在多隐式冲突的场景,优先使用第一种隐式优先级兜底的方案,稳定性更高。
适配你的业务场景
针对Sangria编组器扩展需求,你可以将上述检测逻辑和Shapeless的LabelledGeneric自动推导结合:
- 定义你自己的类映射type class,通过Shapeless自动为case class生成实例
- 替换上述
Foo为你自定义的类映射type class - 扩展Sangria原生Scala编组器时引入上述检测逻辑,即可识别case class等自定义类型为类映射类型
如果需要检测运行时传入值的实际子类型是否有对应type class实例,可搭配TypeTag保留类型信息,实现运行时类型匹配。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

