首页 > 解决方案 > 如何确定一个类是否是父类或特征的子类?

问题描述

在 Scala 中,我们如何确定一个类是父类的子类还是 trait?例如:

trait MyTrait
class MyParentClass()
class MyOtherParentClass()

case class MySubClass() extends MyParentClass with MyTrait
case class MyOtherSubClass() extends MyOtherParentClass

是否可以通过反射 API 来识别类(例如MySubClass从实例化对象MyParentClassMyTrait不实例化对象扩展)?给定一个未知的泛型类型,如果扩展了特定的父类或特征T,我有兴趣让它匹配一个案例:T

def example[T](): Unit = {
    T match {
      case if T extends MyParentClass => ...
      case if T extends MyOtherParentClass => ...
      case if T extends MyOtherTrait => ...
      case _ => default case ...
}

标签: scalagenericsreflectionscala-reflect

解决方案


如果你写

case class MySubClass() extends MyParentClass with MyTrait

然后显然MySubClass扩展MyParentClass,因此您可以使用MyTrait以下方法检查泛型类型T

def test[T](implicit ev: T <:< MyParentClass, ev1: T <:< MyTrait) = ???

test[MySubClass] // compiles

在编译时。


如果问题是你想用 OR 而不是 AND 来检查,那么你可以使用shapeless.OrElseorimplicitbox.Priority

需要两个隐式参数之一的 Scala 方法


我用所需用法的示例更新了问题

看来你想要一个类型类

trait Example[T] {
  def example(): Unit
}
object Example {
  implicit def subtypeOfMyParentClass[T <: MyParentClass] = new Example[T] {
    override def example(): Unit = ???
  }

  implicit def subtypeOfMyOtherParentClass[T <: MyOtherParentClass] = new Example[T] {
    override def example(): Unit = ???
  }

  implicit def subtypeOfMyOtherTrait[T <: MyOtherTrait] = new Example[T] {
    override def example(): Unit = ???
  }

  implicit def default[T] = new Example[T] {
    override def example(): Unit = ???
  }
}

def example[T]()(implicit e: Example[T]): Unit = e.example()

类型类是模式匹配的编译时(即类型级别)替换。

如果隐含之间存在歧义,您可以优先考虑它们。


只是好奇,您是否知道是否有一种方法可以通过简单的单行条件来执行此操作,例如if (T extends from MyParentClass) then ...通过反射 API(是否可以通过classOf[]typeOf[]?)

您可以在运行时执行此操作

import scala.reflect.runtime.universe._

def example[T: TypeTag](): Unit = 
  if (typeOf[T] <:< typeOf[MyParentClass]) ???
  else if (typeOf[T] <:< typeOf[MyOtherParentClass]) ???
  else if (typeOf[T] <:< typeOf[MyOtherTrait]) ???
  else ???

或者

import scala.reflect.ClassTag

def example[T: ClassTag](): Unit = 
  if (classOf[MyParentClass] isAssignableFrom classOf[T]) ???
  else if (classOf[MyOtherParentClass] isAssignableFrom classOf[T]) ???
  else if (classOf[MyOtherTrait] isAssignableFrom classOf[T]) ???
  else ???

或在编译时

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

def example[T](): Unit = macro exampleImpl[T]

def exampleImpl[T: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
  import c.universe._

  if (weakTypeOf[T] <:< typeOf[MyParentClass]) ???
  else if (weakTypeOf[T] <:< typeOf[MyOtherParentClass]) ???
  else if (weakTypeOf[T] <:< typeOf[MyOtherTrait]) ???
  else ???
}

但是隐式和类型是一种更可取的方式,而不是(编译时或特别是运行时)反射。目前还不清楚为什么你需要反思。

https://users.scala-lang.org/t/how-to-access-the-method/6281


推荐阅读