【问题标题】:How to determine if a class is a subclass of a parent class or trait?如何确定一个类是否是父类或特征的子类?
【发布时间】:2020-08-13 00:46:48
【问题描述】:

在 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 ...
}

【问题讨论】:

    标签: scala generics reflection scala-reflect


    【解决方案1】:

    如果你写

    case class MySubClass() extends MyParentClass with MyTrait
    

    那么显然MySubClass 扩展了MyParentClassMyTrait,因此您可以使用T 检查泛型类型

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

    在编译时。


    如果您想用 OR 而不是 AND 来检查,那么您可以使用 shapeless.OrElseimplicitbox.Priority

    Scala method that needs either one of two implicit parameters


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

    看来你想要一个类型类

    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()
    

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

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


    只是好奇,您是否知道是否有一种方法可以通过反射 API 以简单的单行条件(例如 if (T extends from MyParentClass) then ...)来执行此操作(是否可以通过 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

    【讨论】:

    • 谢谢我用所需用法的示例更新了问题
    • 谢谢,这是一个很好的解决方案。只是好奇,您是否知道是否有一种方法可以通过反射 API 以简单的单行条件(例如 if (T extends from MyParentClass) then ...)来执行此操作(是否可以通过 classOf[] 或 typeOf[]?)
    猜你喜欢
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2014-11-08
    • 2014-02-25
    • 2013-02-22
    • 2019-01-03
    • 2023-04-04
    相关资源
    最近更新 更多