8

scala Reflection API (2.10) は、ロードされたクラスを検索し、定義されたトレイトを実装する特定のクラスにリストをフィルタリングする簡単な手段を提供しますか? すなわち;

trait Widget {
  def turn(): Int
}

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

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

Widget を拡張し、それらのクラスをインスタンス化するものをクラス ライブラリで検索したいと考えています。したがって、 and のインスタンスにCogなりSprocketます。

クラスディレクトリを反復処理し、クラス名を形成し、Class.forNameを使用してClassオブジェクトをロードしてチェックするJavaで同様のことを行いました。scala Reflection API を使用すると、より簡単に検索できるようになるのではないかと思っています。これまで見てきたすべての例は、使用可能なクラスを検索することからではなく、インスタンス化された既知のクラスから常に開始されています。

4

1 に答える 1

14

これが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]

を使用してから 10 年が経過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 の比較。getGenericInterfacesLOC の数を把握し、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}"
  }
}
于 2013-07-06T02:51:55.573 に答える