Scala 反射 - 基于特征加载或查找类 [英] Scala Reflection - Loading or finding classes based on trait

查看:40
本文介绍了Scala 反射 - 基于特征加载或查找类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Does the scala reflection API (2.10) provide any easier means of searching the loaded classes and filtering the list to specific classes which implement a defined trait? ie;

trait Widget {
  def turn(): Int
}

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

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

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

I want to search the class library for anything that extends Widget and instantiate those classes. So I would end up with an instance of Cog and Sprocket.

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

I've done similar in Java iterating through the class directories, forming class names and using Class.forName to load a Class object to then check. I'm just wondering if the scala reflection API gives any easier way to search. All examples I've seen thus far have always started from a known class being instantiated, and not from searching over available classes.

推荐答案

这就是 ServiceLoader 的用途.

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

I think the reflection API does make it easier to sort out what you need (i.e., for filtering but not for querying the class loader).

如果用你的短语搜索加载的类",你的意思是已经加载的类,请参阅这个问题 用于获取它们.

If, by your phrase, "searching the loaded classes", you really mean classes that are already loaded, see this question for getting them.

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

You could imagine a widgets library with an initializer that just ensures that all the widget classes it knows about are loaded. Then the client only needs to know the initializer.

型式测试相同.

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"
} 

在何处查找带有类型参数的内容:

Where you're looking for something with type parameters:

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 已经十年了,而且谁不需要复习:

In case it's been ten years since you used ServiceLoader, and who doesn't need a refresher:

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 中找到你想要的东西,但后来我结束了练习.

Comparing Scala and Java. I was going to get a sense of how many LOC to getGenericInterfaces and find what you want in Scala, but then I put an end to the exercise.

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}"
  }
}

这篇关于Scala 反射 - 基于特征加载或查找类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆