簡體   English   中英

Scala 使用擴展 trait 的類的反射訪問運行時類型的成員

[英]Scala accessing members of runtime types using reflection of a class that extends a trait

假設我有一個MyItem trait 並且它的伴生對象有一個apply()函數,它創建一個名為SubItem的類實例,它從MyItem擴展:

import scala.reflect.runtime.{universe => ru}

trait MyItem {
  import MyItem._
  def num: Option[Int]
}

object MyItem {
  class SubItem(val num: Option[Int]) extends MyItem 

  def apply(num: Option[Int]): MyItem = new SubItem(num) // creates SubItem
}

def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]

val modifiedItem = MyItem(Some(11))
val theType = getTypeTag(modifiedItem).tpe

如果您打印出上面的theType ,它將是MyItem

此時,如果您嘗試使用 反射來修改字段num ,它將不起作用,因為MyItemnum作為方法,而不是字段(如在MyItem.SubItem ):

val m = ru.runtimeMirror(modifiedItem.getClass.getClassLoader)
val numTermSymb = theType.decl(ru.TermName("num")).asTerm
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectField(numTermSymb)  // not going to work
numFieldMirror.get
numFieldMirror.set(Some(999))  // my goal, if possible

不幸的是,上面會拋出scala.ScalaReflectionException: expected a field or an accessor method symbol, you provided method num

相反,您應該執行以下操作:

val numTermSymb = theType.decl(ru.TermName("num")).asMethod
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectMethod(numTermSymb)
numFieldMirror() // returns `Some(11)`

但我的目標是訪問擴展 MyItem 的 SubItem 類並修改其 field 如何獲取MyItem類型的實例並修改MyItem的方法num正在訪問的MyItem.SubItem中的字段?

代替

val theType = getTypeTag(modifiedItem).tpe

val theType = ru.typeOf[MyItem.SubItem]

如果你知道類的名稱靜態或

val theType = m.staticClass("pckg.MyItem.SubItem").typeSignature

如果您動態知道類的名稱。


嘗試

val className = modifiedItem.getClass.getName.replace('$', '.')
val theType = m.staticClass(className).typeSignature

實際上, m.staticClass(className).typeSignatureAnyRef with pckg.MyItem {...}即子項的父母/ SubItem

theType =:= ru.typeOf[MyItem.SubItem] // false

所以,雖然numFieldMirror.get/set有效,但最好使用toType而不是typeSignature

val className = modifiedItem.getClass.getName.replace('$', '.')
val theType = m.staticClass(className).toType

theType =:= ru.typeOf[MyItem.SubItem] // true

另一種方式是純 Scala 式的

val instanceMirror = m.reflect(modifiedItem) 
val theType = instanceMirror.symbol.toType

theType =:= ru.typeOf[MyItem.SubItem] // true

它甚至更好,因為不對字符串使用容易出錯和依賴於實現的操作( replace )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM