scala反射API(2.10)是否提供了更容易的方法来搜索加载的类并将列表过滤到实现定义特征的特定类?即;
trait Widget {
def turn(): Int
}
class Cog extends Widget {
def turn() = {
5
}
}
class Sprocket extends Widget {
def turn() = {
10
}
}
我想在类库中搜索任何扩展Widget并实例化这些类的东西。所以我最后会得到一个Cog
和Sprocket
的实例。
我在Java中也做过类似的事情,遍历类目录,形成类名,并使用class.forName加载一个class对象进行检查。我只是想知道scala反射API是否提供了更容易的搜索方法。到目前为止,我看到的所有例子都是从实例化的已知类开始的,而不是从搜索可用的类开始的。
这就是ServiceLoader
的作用。
我认为反射API确实可以更容易地整理出您需要的东西(即,用于过滤,而不是用于查询类加载器)。
如果你所说的"搜索已加载的类"真的是指已经加载的类,请参阅这个问题以获取它们。
您可以想象一个具有初始值设定项的小部件库,它只确保加载它所知道的所有小部件类。那么客户端只需要知道初始值设定项。
型式试验相同。
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}"
}
}