कोटलिन में संशोधित कीवर्ड कैसे काम करता है?


144

मैं reifiedकीवर्ड के उद्देश्य को समझने की कोशिश कर रहा हूं , जाहिर है कि यह हमें जेनरिक पर प्रतिबिंब बनाने की अनुमति दे रहा है

हालाँकि, जब मैं इसे छोड़ता हूँ तो यह ठीक काम करता है। किसी को भी समझाने के लिए परवाह है जब यह एक वास्तविक अंतर बनाता है ?


क्या आप वाकई जानते हैं कि प्रतिबिंब क्या है? इसके अलावा, क्या आपने टाइप इरैचर के बारे में सुना है?
मिबक

3
सामान्य प्रकार के पैरामीटर रनटाइम में मिटा दिए जाते हैं, यदि आप पहले से ही नहीं हैं तो टाइप इरेज़र के बारे में पढ़ें। इनलाइन फ़ंक्शंस पर रिफ़ाइन्ड प्रकार के पैरामीटर न केवल विधि बॉडी को इनलाइन करते हैं, बल्कि जेनेरिक टाइप पैरामीटर भी आपको T :: class.java (जो आप सामान्य जेनेरिक प्रकारों के साथ नहीं कर सकते हैं) जैसी चीज़ों की अनुमति देते हैं। एक टिप्पणी के रूप में लाना क्योंकि मेरे पास अभी पूर्ण उत्तर देने का समय नहीं है ..
F. जॉर्ज

यह प्रतिबिंब पर भरोसा किए बिना और तर्क के रूप में टाइप पास किए बिना किसी फ़ंक्शन के ठोस सामान्य प्रकार तक पहुंच प्राप्त करने की अनुमति देता है।
BladeCoder

जवाबों:


368

टीएल; डीआर: किसके लिए reifiedअच्छा है

fun <T> myGenericFun(c: Class<T>) 

जैसे सामान्य कार्य के शरीर में myGenericFun, आप प्रकार तक नहीं पहुँच सकते Tक्योंकि यह केवल संकलन समय पर उपलब्ध है, लेकिन रनटाइम पर मिटा दिया गया है। इसलिए, यदि आप फ़ंक्शन बॉडी में एक सामान्य वर्ग के रूप में जेनेरिक प्रकार का उपयोग करना चाहते हैं, तो आपको कक्षा में दिखाए गए पैरामीटर के रूप में स्पष्ट रूप से पास करने की आवश्यकता है myGenericFun

यदि आप किसी inlineफ़ंक्शन को किसी reified के साथ बनाते हैं T, तो Tरनटाइम पर भी एक्सेस किया जा सकता है और इस प्रकार आपको Class<T>इसके अतिरिक्त पास करने की आवश्यकता नहीं है । आप इसके साथ काम कर सकते हैं Tजैसे कि यह एक सामान्य वर्ग था, उदाहरण के लिए, आप जाँच सकते हैं कि क्या एक चर का एक उदाहरण है T , जिसे आप आसानी से देख सकते हैं myVar is T:।

प्रकार के inlineसाथ इस तरह के एक समारोह इस प्रकार है:reifiedT

inline fun <reified T> myGenericFun()

कैसे reifiedकाम करता है

आप केवल reifiedएक inlineफ़ंक्शन के साथ संयोजन में उपयोग कर सकते हैं । ऐसा फ़ंक्शन कंपाइलर को फ़ंक्शन के बाइटकोड को हर उस स्थान पर कॉपी करता है जहां फ़ंक्शन का उपयोग किया जा रहा है (फ़ंक्शन "इनबिल्ड" हो रहा है)। जब आप एक इनलाइन फ़ंक्शन को रिफ़ाइंड प्रकार के साथ कॉल करते हैं, तो कंपाइलर वास्तविक प्रकार को एक तर्क के रूप में जानता है और उत्पन्न बाइटकोड को सीधे संबंधित वर्ग का उपयोग करने के लिए संशोधित करता है। इसलिए जैसे कॉल myVar is Tबन myVar is String(यदि प्रकार तर्क थे Stringबाईटकोड में और रनटाइम पर)।


उदाहरण

आइए एक उदाहरण देखें जो दिखाता है कि कितना उपयोगी reifiedहो सकता है। हम Stringकॉल के लिए एक एक्सटेंशन फ़ंक्शन बनाना चाहते हैं जो toKotlinObjectफ़ंक्शन के जेनेरिक प्रकार द्वारा निर्दिष्ट प्रकार के साथ एक JSON स्ट्रिंग को सादे कोटलिन ऑब्जेक्ट में बदलने की कोशिश करता है T। हम इसके लिए उपयोग कर सकते हैं com.fasterxml.jackson.module.kotlinऔर पहला तरीका निम्नलिखित है:

क) पहले प्रकार के बिना पुनरीक्षित प्रकार

fun <T> String.toKotlinObject(): T {
      val mapper = jacksonObjectMapper()
                                                        //does not compile!
      return mapper.readValue(this, T::class.java)
}

readValueविधि एक प्रकार है कि यह पार्स करने के लिए चाहिए था लेता JsonObjectहै। यदि हम Classप्रकार के पैरामीटर को प्राप्त करने की कोशिश करते हैं T, तो कंपाइलर शिकायत करता है: "T 'को रिवाइज्ड टाइप पैरामीटर के रूप में उपयोग नहीं किया जा सकता है। इसके बजाय एक वर्ग का उपयोग करें।"

बी) स्पष्ट Classपैरामीटर के साथ समाधान

fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, c.java)
}

समाधान के लिए, Classकी Tएक विधि पैरामीटर, जो तब के लिए एक तर्क के रूप में इस्तेमाल किया जा सकता है readValue। यह काम करता है और जेनेरिक जावा कोड में एक सामान्य पैटर्न है। इसे इस प्रकार कहा जा सकता है:

data class MyJsonType(val name: String)

val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)

ग) कोटलिन रास्ता: reified

प्रकार पैरामीटर के inlineसाथ फ़ंक्शन का उपयोग करना फ़ंक्शन को अलग तरीके से लागू करना संभव बनाता है:reifiedT

inline fun <reified T: Any> String.toKotlinObject(): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, T::class.java)
}

लेने के लिए कोई ज़रूरत नहीं है Classकी Tइसके अतिरिक्त, Tइस्तेमाल किया जा सकता है कि यह एक साधारण वर्ग था। क्लाइंट के लिए कोड इस तरह दिखता है:

json.toKotlinObject<MyJsonType>()

महत्वपूर्ण नोट: जावा के साथ काम करना

reifiedप्रकार के साथ एक इनलाइन फ़ंक्शन जावा कोड से कॉल करने योग्य नहीं है


6
आपकी व्यापक प्रतिक्रिया के लिए धन्यवाद! वह वास्तव में समझ में आता है। बस एक बात मैं सोच रहा हूं, अगर फ़ंक्शन को वैसे भी इनबिल्ड किया जा रहा है, तो इसकी आवश्यकता क्यों है? यह वैसे भी मिटाता है और फ़ंक्शन को इनलाइन करता है? यह मेरे लिए एक तरह की बर्बादी लगती है, यदि आप फ़ंक्शन को इनलाइन करते हैं तो आप उपयोग किए जा रहे प्रकार को इनलाइन कर सकते हैं या क्या मैं यहां कुछ गलत देख रहा हूं?
hl3mukkel

6
आपकी प्रतिक्रिया के लिए धन्यवाद, वास्तव में मैं कुछ का उल्लेख करना भूल जाता हूं जो आपको उत्तर दे सकता है: एक सामान्य इनलाइन फ़ंक्शन को जावा से बुलाया जा सकता है, लेकिन एक प्रकार का कोई भी संशोधित पैरामीटर नहीं कर सकता है! मुझे लगता है कि यह एक कारण है कि इनलाइन फ़ंक्शन के प्रत्येक प्रकार के पैरामीटर को स्वचालित रूप से संशोधित नहीं किया जाता है।
s1m0nw1

क्या होगा यदि फ़ंक्शन एकीकृत और गैर-पुनरीक्षित मापदंडों का मिश्रण है? यह जावा के किसी भी रास्ते से बुलाया जाने योग्य नहीं है, सभी प्रकार के मापदंडों को स्वचालित रूप से क्यों नहीं संशोधित करता है? कोटलिन को सभी प्रकार के मापदंडों के लिए स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता क्यों है?
वैरावन

1
क्या होगा यदि स्टैक में ऊपरी कॉलर्स को json.toKotlinObject <MyJsonType> () की आवश्यकता नहीं है, लेकिन विभिन्न वस्तुओं के लिए json.toKotlinObject <T> ()?
सात

1

सरल

* पुनरीक्षण संकलन समय पर उपयोग करने की अनुमति देना है (डी कार्य के अंदर टी का उपयोग करने के लिए)

उदाहरण के लिए:

 inline fun <reified T:Any>  String.convertToObject(): T{

    val gson = Gson()

    return gson.fromJson(this,T::class.java)

}

जैसे उपयोग कर रहे हैं:

val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
  println(user.name)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.