أي طريقة للوصول إلى نوع إعلان خيار Scala في وقت التشغيل باستخدام الانعكاس؟

StackOverflow https://stackoverflow.com/questions/2664114

سؤال

لذلك ، لدي فئة Scala التي تبدو هكذا:

class TestClass {
  var value: Option[Int] = None
}

وأنا أتناول مشكلة حيث لدي قيمة سلسلة وأريد إجبارها على هذا الخيار [int] في وقت التشغيل باستخدام الانعكاس. لذلك ، في جزء آخر من التعليمات البرمجية (لا يعرف شيئًا عن TestClass) لدي بعض التعليمات البرمجية مثل هذا:

def setField[A <: Object](target: A, fieldName: String, value: String) {
  val field = target.getClass.getDeclaredField(fieldName)
  val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ? 
  field.set(target, coercedValue)   
}

للقيام بذلك ، أحتاج إلى معرفة أن الحقل هو خيار وأن معلمة النوع للخيار هي int.

ما هي خياراتي لمعرفة أن نوع "القيمة" هو الخيار [int] في وقت التشغيل (أي باستخدام الانعكاس)؟

لقد رأيت مشاكل مماثلة تم حلها عن طريق التعليق على الحقل ، على سبيل المثال egtionType (int.class). أفضل حل لا يتطلب تعليقات على هدف الانعكاس إن أمكن.

هل كانت مفيدة؟

المحلول

إنه أمر مريح تمامًا باستخدام API Java 1.5 Reflection:

 def isIntOption(clasz: Class[_], propertyName: String) = {
   var result = 
     for {
       method <- cls.getMethods
       if method.getName==propertyName+"_$eq"
       param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
     } yield
       param.getActualTypeArguments.toList == List(classOf[Integer]) 
       && param.getRawType == classOf[Option[_]]
   if (result.length != 1)
     throw new Exception();
   else
     result(0)
 }

نصائح أخرى

على مستوى رمز البايت ، لم تحصل Java على الأدوية الجيرية. يتم تنفيذ الأعياد باستخدام تعدد الأشكال ، لذلك بمجرد تجميع رمز المصدر (في هذه الحالة ScalA) ، تختفي الأنواع العامة (وهذا ما يسمى اكتب المحو ). هذا لا يمكن جمع معلومات نوع وقت التشغيل العام عبر التفكير.

من الممكن-على الرغم من القليل من القذرة-الحل هو الحصول على نوع وقت التشغيل الخاص بالخاصية التي تعرف أنها تحتوي على نفس النوع مثل المعلمة العامة. لحالات الخيار يمكننا استخدامها get عضو

object Test {

  def main(args : Array[String]) : Unit = {
    var option: Option[_]= None
    println(getType(option).getName)
    option = Some(1)
    println(getType(option).getName)

  }

  def getType[_](option:Option[_]):Class[_]= {
         if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
  }
}
class TestClass {
  var value: Option[Int] = None
// ...

  def doSomething {
    value match {
      case Some(i) => // i is an Int here
      case None =>
      // No other possibilities
    }
  }
}

المشكلة هي أن JVM ينفذ الأداء من خلال محو النوع. لذلك من المستحيل اكتشاف من خلال انعكاس أن نوع من value هو Option[Int] لأنه في وقت التشغيل ليس كذلك في الواقع: إنه فقط Option!

في 2.8 يجب أن تكون قادرًا على الاستخدام Manifests مثله:

var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top