2016-07-03 10 views
5

यह मानते हुए कि मैं एक सामान्य सुपर क्लास है:स्कैला प्रतिबिंब में, एक ठोस उपclass के सामान्य प्रकार पैरामीटर कैसे प्राप्त करें?

class GenericExample[T](
         a: String, 
         b: T 
         ) { 

    def fn(i: T): T = b 
} 

और एक ठोस उपवर्ग:

case class Example(
        a: String, 
        b: Int 
       ) extends GenericExample[Int](a, b) 

मैं समारोह "fn" स्केला प्रतिबिंब द्वारा की प्रकार पैरामीटर प्राप्त करना चाहते हैं, तो मैं चयन और फिल्टर अपने सदस्यों के माध्यम से:

import ScalaReflection.universe._ 

val baseType = typeTag[Example] 

val member = baseType 
    .tpe 
    .member(methodName: TermName) 
    .asTerm 
    .alternatives 
    .map(_.asMethod) 
    .head 

    val paramss = member.paramss 
    val actualTypess: List[List[Type]] = paramss.map { 
     params => 
     params.map { 
      param => 
      param.typeSignature 
     } 
    } 

मैं स्केला उम्मीद कर रहा था मुझे सही परिणाम है, जो List(List(Int)) है देने के लिए, के बजाय मैं केवल छ ओ.टी. सामान्य List(List(T))

दस्तावेज़ मुझे लगता है कि typeSignature पाया माध्यम से crunching दोषी है:

* This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an 
* instantiation of a generic type. 

और यह मुझे पता चलता है विकल्प का उपयोग करें:

def typeSignatureIn(site: Type): Type 

हालांकि, बाद से वर्ग उदाहरण नहीं है लंबे जेनेरिक, टाइपटाग [उदाहरण] से साइट प्राप्त करने का कोई तरीका नहीं है, क्या कोई मुझे बता सकता है कि टाइपऑफ [Int] केवल टाइपटाग [उदाहरण] दिया गया है? या ऐसा करने का कोई तरीका नहीं है और मुझे जावा प्रतिबिंब में वापस जाना है?

आपकी मदद के लिए बहुत बहुत धन्यवाद।

अद्यतन: कुछ त्वरित परीक्षण मैंने पाया कि यहां तक ​​कि MethodSymbol.returnType इरादा है, तो निम्न कोड के रूप में काम नहीं करता है के बाद:

member.returnType 

भी T उपज, annd यह सही नहीं किया जा सकता asSeenFrom द्वारा, निम्नलिखित कोड परिणाम नहीं बदलती:

member.returnType.asSeenFrom(baseType.tpe, baseType.tpe.typeSymbol.asClass) 
+0

यहां तक ​​कि इससे पहले कि वास्तव में अपने प्रश्न को पढ़ चुके हैं। स्कैला के साथ अपने पूरे अनुभव के दौरान, इसकी मूल अवधारणाओं में से एक को संकलक के रूप में उतना ही प्रतिनिधि देना है। तो प्रतिबिंब उन चीजों में से एक नहीं है जो आप स्कैला में करेंगे। हालांकि आप मैक्रोज़ या संदर्भ सीमाओं (मैनिफ़ेस्ट और क्लासमैनिफेट्स) का उपयोग कर सकते हैं – caeus

+0

बहिष्कृत होने की प्रक्रिया में प्रकट होता है? और क्लासमैनिफेस्ट का नाम बदलकर क्लासटाग कर दिया गया? मुझे आशा है कि मैं कम से कम मिटाए गए क्लासटैग को विधि से प्राप्त कर सकता हूं, लेकिन फिर भी ऐसा करने में असमर्थ है। – tribbloid

उत्तर

0

मैं अपने समाधान पोस्टिंग कर रहा हूँ: मैं लगता है कि स्कैला के डिजाइन के कारण कोई विकल्प नहीं है:

स्कैला प्रतिबिंब & जावा प्रतिबिंब में विधियों के बीच मुख्य अंतर करीना है: स्कैला विधि compri ब्रैकेट के कई जोड़े के एसईएस, तर्कों के साथ एक विधि को बुलाते हुए पहले केवल एक अज्ञात वर्ग बनाता है जो ब्रैकेट के अधिक जोड़े ले सकता है, या यदि कोई और ब्रैकेट नहीं छोड़ा गया है, तो एक NullaryMethod क्लास (a.k.a. कॉल-बाय-नाम) जिसे विधि के परिणाम देने के लिए हल किया जा सकता है। इसलिए स्काला विधि के प्रकार केवल इस स्तर पर हल किए जाते हैं, जब विधि & NullaryMethod हस्ताक्षर में विधि पहले से ही टूट जाती है।

नतीजतन यह स्पष्ट हो जाता परिणाम प्रकार केवल हो सकता है कि प्रत्यावर्तन का उपयोग कर पाने:

private def methodSignatureToParameter_ReturnTypes(tpe: Type): (List[List[Type]], Type) = { 
    tpe match { 
     case n: NullaryMethodType => 
     Nil -> n.resultType 
     case m: MethodType => 
     val paramTypes: List[Type] = m.params.map(_.typeSignatureIn(tpe)) 
     val downstream = methodSignatureToParameter_ReturnTypes(m.resultType) 
     downstream.copy(_1 = List(paramTypes) ++ methodSignatureToParameter_ReturnTypes(m.resultType)._1) 
     case _ => 
     Nil -> tpe 
    } 
    } 

    def getParameter_ReturnTypes(symbol: MethodSymbol, impl: Type) = { 

    val signature = symbol.typeSignatureIn(impl) 
    val result = methodSignatureToParameter_ReturnTypes(signature) 
    result 
    } 

कहाँ impl वर्ग कि विधि का मालिक है, और symbol आप स्केला प्रतिबिंब

द्वारा Type.member(s) से क्या प्राप्त है
+0

कहा जा रहा है कि, मुझे अभी भी उम्मीद है कि स्कैला और जावा प्रतिबिंब में विधि अधिक इंटरऑपरेबल हो सकती है, क्योंकि दोनों का अपना फायदा होता है: जावा विधि का आह्वान करने के लिए बहुत तेज़ तरीका है, लेकिन जेवीएम में रनटाइम टाइप चेक काफी ढीला है, कोई पूर्णता नहीं है यहां: - < – tribbloid

4

वहाँ दो appr हैं जो oaches मेरा सुझाव कर सकते हैं:

1) आधार वर्ग से सामान्य प्रकार प्रकट:

import scala.reflect.runtime.universe._ 

class GenericExample[T: TypeTag](a: String, b: T) { 
    def fn(i: T) = "" + b + i 
} 

case class Example(a: String, b: Int) extends GenericExample[Int](a, b) {} 

val classType = typeOf[Example].typeSymbol.asClass 
val baseClassType = typeOf[GenericExample[_]].typeSymbol.asClass 
val baseType = internal.thisType(classType).baseType(baseClassType) 

baseType.typeArgs.head // returns reflect.runtime.universe.Type = scala.Int 

2) अंतर्निहित विधि है जो रिटर्न जोड़े के प्रकार:

import scala.reflect.runtime.universe._ 

class GenericExample[T](a: String, b: T) { 
    def fn(i: T) = "" + b + i 
} 

case class Example(a: String, b: Int) extends GenericExample[Int](a, b) 

implicit class TypeDetector[T: TypeTag](related: GenericExample[T]) { 
    def getType(): Type = { 
    typeOf[T] 
    } 
} 

new Example("", 1).getType() // returns reflect.runtime.universe.Type = Int 
+0

मुझे अपने ज्यादातर मामलों में डर है जेनेरिक एक्सप्ल्यूम अज्ञात है और विरासत के मनमाना ग्राफ में गहरा दफनाया गया है, इसलिए एक साथी डिटेक्टर लिखना संभव नहीं है, लेकिन मैं पहले समाधान को ग्रोक करने का प्रयास करूंगा, धन्यवाद आपके उत्तर के लिए बहुत कुछ! – tribbloid

+0

काम नहीं करता है: त्रुटि: (72, 20) नहीं मिला: मूल्य आंतरिक वैल बेस टाइप = internal.this टाइप (क्लास टाइप) .बेस टाइप (बेस क्लास टाइप)। मैं लाइब्रेरी – tribbloid

+0

के साथ संगतता के लिए स्कैला 2.10.6 का उपयोग कर रहा हूं, मुझे लगता है कि मेरे पास अब एक सुराग है, सुपर जेनेरिक क्लास से MethodSymbol हमेशा टाइप पैरामीटर मिटा देता है, इसे रोकने के लिए मुझे इसके बजाय विधि टाइप का उपयोग करना होगा। – tribbloid

संबंधित मुद्दे