【问题标题】:Scala Reflection - Loading or finding classes based on traitScala Reflection - 基于特征加载或查找类
【发布时间】:2013-07-03 16:03:01
【问题描述】:

scala 反射 API (2.10) 是否提供更简单的方法来搜索加载的类并将列表过滤到实现定义特征的特定类? 即;

trait Widget {
  def turn(): Int
}

class Cog extends Widget {
  def turn() = {
    5
  }
}

class Sprocket extends Widget {
  def turn() = {
   10
  }
}

我想在类库中搜索任何扩展 Widget 并实例化这些类的东西。所以我最终会得到CogSprocket 的实例。

我在 Java 中完成了类似的操作,遍历类目录、形成类名并使用 Class.forName 加载 Class 对象以进行检查。我只是想知道 scala 反射 API 是否提供了更简单的搜索方式。到目前为止,我看到的所有示例都是从正在实例化的已知类开始的,而不是从搜索可用类开始的。

【问题讨论】:

    标签: scala reflection scala-2.10


    【解决方案1】:

    这就是ServiceLoader 的用途。

    我认为反射 API 确实可以更轻松地整理出您需要的内容(即过滤而不是查询类加载器)。

    如果用您的说法“搜索加载的类”,您的意思是已经加载的类,请参阅this question 获取它们。

    您可以想象一个带有初始化程序的小部件库,它只是确保加载它知道的所有小部件类。那么客户端只需要知道初始化器即可。

    型式测试是一样的。

    val need = typeOf[Whatsit[Cog]]
    for (x <- (ServiceLoader load classOf[Whatsit[_]]).asScala) { 
      val im = currentMirror reflect x 
      if (im.symbol.toType weak_<:< need)
        Console println s"$x is what I need"
      else
        Console println s"$x is not what I need, I'm looking for a $need"
    } 
    

    你在哪里寻找带有类型参数的东西:

    trait Whatsit[+A <: Widget] {
      def widget: A
    }
    
    class Engine extends Whatsit[Cog] {
      def widget = new Cog
    }
    
    class FlyWheel extends Whatsit[Sprocket] {
      def widget = new Sprocket
    }
    

    示例:

    widgets.Engine@f9da0cd is what I need
    widgets.FlyWheel@4cfdbb9f is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog]
    

    如果你使用ServiceLoader 已经十年了,谁不需要复习:

    apm@mara:~/tmp$ ls -R META-INF
    META-INF:
    MANIFEST.MF  services
    
    META-INF/services:
    widgets.Whatsit  widgets.Widget
    apm@mara:~/tmp$ cat META-INF/services/widgets.Widget
    widgets.Cog
    widgets.Sprocket
    apm@mara:~/tmp$ cat META-INF/services/widgets.Whatsit 
    widgets.Engine
    widgets.FlyWheel
    

    东西:

    package widgets
    
    trait Widget {
      def turn(): Int
      override def toString = s"Widget ${getClass.getSimpleName}"
    }
    
    class Cog extends Widget {
      def turn() = 5
    }
    
    class Sprocket extends Widget {
      def turn() = 10
    }
    
    trait Whatsit[+A <: Widget] {
      def widget: A
      override def toString = s"Whatsit ${getClass.getSimpleName} of $widget"
    }
    
    class Engine extends Whatsit[Cog] {
      def widget = new Cog
    }
    
    class FlyWheel extends Whatsit[Sprocket] {
      def widget = new Sprocket
    }
    

    比较 Scala 和 Java。我打算了解getGenericInterfaces 有多少 LOC 并在 Scala 中找到你想要的,但后来我结束了这个练习。

    package findwidgets
    
    import reflect._
    import reflect.runtime.universe._
    import reflect.runtime.currentMirror
    import scala.collection.JavaConverters._
    import java.util.ServiceLoader
    
    object Test extends App {
      import widgets.{ Widget, Whatsit, Cog }
      val ws = (ServiceLoader load classOf[Widget]).asScala
      for (w <- ws) {
        Console println s"Turn a ${w.getClass} by ${w.turn}"
      }
      val need = typeOf[Whatsit[Cog]]
      for (x <- (ServiceLoader load classOf[Whatsit[Cog]]).asScala) {
        val im = currentMirror reflect x
        if (im.symbol.toType weak_<:< need)
          Console println s"$x is what I need"
        else
          Console println s"$x is not what I need, I'm looking for a $need"
        // java says:
        if (classOf[Whatsit[Cog]] isAssignableFrom x.getClass)
          Console println s"Um, OK, I'll take the $x"
        else
          Console println s"${classOf[Whatsit[Cog]]} isn't ass'able from ${x.getClass}"
      }
    }
    

    【讨论】:

    • 这不是要求程序员将他的接口显式声明为服务并在META-INF/services/...中列出其所有实现吗?
    • 是的,关键是图书馆会告诉你它提供了什么。与其尝试扫描已知 Universe 中的小部件,不如在已知位置有一个资源,您可以查询给定的类加载器。我粘贴了其他部分仅供参考。
    • 太棒了!谢谢索姆!这正是我所需要的。
    • @Doswell 值得添加您加载的服务可以提供 api 来列出可用的小部件。
    • 对于那些正在使用 sbt 并且不确定将 META-INF 文件夹放在哪里的人:stackoverflow.com/questions/32916024/…
    猜你喜欢
    • 2017-07-05
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    • 2022-01-22
    • 2012-07-10
    • 2015-05-26
    相关资源
    最近更新 更多