socが書いたことに基づいて、私はこれを得ました:
import scala.reflect.runtime.universe._
val members = typeOf[MyClass].members.filter(_.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] => true
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] => true
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] => true
case _ => false
})
パターンマッチについて説明します。aval
または anの型はobject
直接比較できますが、関数の型は少し異なります。ここでは、パラメーター リストのないメソッドとアリティ ゼロのパラメーター リストを持つメソッドを照合しています。
ここには、socの回答と比較していくつかの違いがあります。まず、members
代わりにを使用しdeclarations
ます。これは、継承されたメンバーと、MyClass
それ自体で宣言されたメンバーを返します。
次に、型メンバーではなく値メンバーであることを確認します。値に対してのみメソッドを呼び出すことができるため、不必要かもしれませんが、合理的な制限に見えました。更新。このisValue
メソッドは 2.10.0-RC1 では使用できなくなったため、チェックを外しました。
最後に、<:<
各親が等しいかどうかをチェックする代わりに使用します。
では、召喚へ。呼び出しはメンバーの種類に依存するため、上記のコードを変更します。そのため、フィルター処理と呼び出しを同時に行うことをお勧めします。それが求められていると仮定して、私も から に変更しmembers
ます。nonPrivateMembers
更新。nonPrivateMembers
2.10.0-RC1 では使用できなくなりましたfilter(!_.isPrivate)
。必要に応じて使用してください。
typeOf
また、REPL のミラーでは機能しない の使用も避けます。更新。2.10.0 では RC1typeOf
は問題なく動作していますが、実装の骨子はそのままにしておきます。
上記のすべては、基本的に物事の構造に関係しています: 型のメンバーが何であるか、それらがどのような種類のメンバーであるかなどです。このようなものを使いたいときは、鏡が必要です。
何か (クラス、メソッド、obj など) のシンボルまたは型がある場合はいつでも、mirrorを介してそのものに作用します。オブジェクトのインスタンスに (反射的に) 作用するには、インスタンス ミラーが必要です。メソッドを操作するには、メソッド ミラーが必要です。
それでは、要求されたことを実行する関数を作成してみましょう。
import scala.reflect.runtime.universe._
def invoke[Target : TypeTag](obj: Any): Seq[Target] = {
val mirror = runtimeMirror(obj.getClass.getClassLoader)
val insMirror = mirror reflect obj
val originType = insMirror.symbol.typeSignature
val targetType = typeTag[Target].tpe
val members = originType.members
val result = members collect (member => member.typeSignature match {
case tpe if tpe <:< typeOf[ThirdParty] =>
if (member.isModule)
(insMirror reflectModule member.asModule).instance
else
(insMirror reflectField member.asTerm).get
case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] =>
(insMirror reflectMethod member.asMethod).apply()
})
result.map(_.asInstanceOf[Target]).toSeq
}
ネストされたモジュールは Scala 2.10.0-M4 では復元できないことに注意してください -- これは M5 または RC1 で可能になるはずです。このコードを M4 でテストするには、モジュール コードを に置き換えますnull
。
サンプルは次のとおりです。
scala> class MyClass {
object objA extends ThirdParty
object objB extends WeatherIcon
val aVal = new ThirdParty {}
val bVal = new WeatherIcon {}
def aDef = new ThirdParty {}
def bDef = new WeatherIcon {}
def anotherDef() = new ThirdParty {}
def yetAnotherDef() = new WeatherIcon {}
}
defined class MyClass
scala> invoke[ThirdParty](new MyClass)
res88: Seq[ThirdParty] = List(MyClass$$anon$5@c250cba, MyClass$$anon$3@54668d90, MyClass$$anon$1@18d8143a, null)