如何确定 class 是父 class 的子 class 还是特征?

How to determine if a class is a subclass of a parent class or trait?

在 Scala 中,我们如何确定 class 是父 class 的子 class 还是特征?例如:

trait MyTrait
class MyParentClass()
class MyOtherParentClass()

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

是否可以在不实例化对象和通过反射 API 的情况下识别 class(例如 MySubClass 是否从 MyParentClassMyTrait 扩展?给定一个未知的泛型类型 T,如果 T 扩展了一个特定的父 class 或特征:

,我有兴趣让它匹配一个案例
def example[T](): Unit = {
    T match {
      case if T extends MyParentClass => ...
      case if T extends MyOtherParentClass => ...
      case if T extends MyOtherTrait => ...
      case _ => default case ...
}

如果你写

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


I updated the question with an example of the desired usage

看来你想要一个类型class

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

类型 class 是模式匹配的 compile-time(即 type-level)替代。

如果隐式之间存在歧义,您可以确定它们的优先级。


Just curious, do you know if there is a way to do this in a simple one line conditional such as if (T extends from MyParentClass) then ... through reflection APIs (is it possible through classOf[] or 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 ???
}

但是隐式和类型是比(compile-time 或尤其是运行时)反射更可取的方式。根本不清楚为什么需要反射。

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