Kotlin
एक्सटेंशन के तरीके
खोज…
वाक्य - विन्यास
- fun TypeName.extensionName (params, ...) {/ * शरीर * /} // घोषणा
- मज़ा <टी: कोई भी
- myObj.extensionName (args, ...) // मंगलाचरण
टिप्पणियों
एक्सटेंशन का समाधान सांख्यिकीय रूप से किया जाता है । इसका मतलब है कि उपयोग की जाने वाली विस्तार विधि उस चर के संदर्भ-प्रकार से निर्धारित होती है जिसे आप एक्सेस कर रहे हैं; यह कोई फर्क नहीं पड़ता कि रनवे पर चर का प्रकार क्या है, उसी एक्सटेंशन विधि को हमेशा कहा जाएगा। ऐसा इसलिए है क्योंकि एक्सटेंशन विधि की घोषणा करने से वास्तव में एक सदस्य को रिसीवर प्रकार में नहीं जोड़ा जाता है ।
शीर्ष स्तर के एक्सटेंशन
शीर्ष स्तर के विस्तार के तरीके एक वर्ग के भीतर समाहित नहीं हैं।
fun IntArray.addTo(dest: IntArray) {
for (i in 0 .. size - 1) {
dest[i] += this[i]
}
}
विस्तार विधि के ऊपर IntArray
के प्रकार के लिए परिभाषित किया गया है। ध्यान दें कि जिस ऑब्जेक्ट के लिए एक्सटेंशन विधि को परिभाषित किया गया है (जिसे रिसीवर कहा जाता है) this
कीवर्ड का उपयोग करके एक्सेस किया जाता है।
इस विस्तार को ऐसा कहा जा सकता है:
val myArray = intArrayOf(1, 2, 3)
intArrayOf(4, 5, 6).addTo(myArray)
संभावित नुकसान: एक्सटेंशन को सांख्यिकीय रूप से हल किया जाता है
जिस एक्सटेंशन विधि को कॉल किया जाना है वह संकलन-समय पर चर के संदर्भ-प्रकार के आधार पर पहुँचा जा रहा है। इससे कोई फर्क नहीं पड़ता कि रनवे पर वैरिएबल का प्रकार क्या है, उसी एक्सटेंशन विधि को हमेशा कहा जाएगा।
open class Super
class Sub : Super()
fun Super.myExtension() = "Defined for Super"
fun Sub.myExtension() = "Defined for Sub"
fun callMyExtension(myVar: Super) {
println(myVar.myExtension())
}
callMyExtension(Sub())
उपरोक्त उदाहरण "Defined for Super"
प्रिंट करेगा, क्योंकि घोषित प्रकार का चर myVar
Super
।
नमूना एक मानव पठनीय स्ट्रिंग प्रदान करने के लिए लंबे समय तक फैली हुई है
मानव पठनीय स्ट्रिंग को प्रस्तुत करने के लिए Int
या Long
प्रकार के किसी भी मूल्य को देखते हुए:
fun Long.humanReadable(): String {
if (this <= 0) return "0"
val units = arrayOf("B", "KB", "MB", "GB", "TB", "EB")
val digitGroups = (Math.log10(this.toDouble())/Math.log10(1024.0)).toInt();
return DecimalFormat("#,##0.#").format(this/Math.pow(1024.0, digitGroups.toDouble())) + " " + units[digitGroups];
}
fun Int.humanReadable(): String {
return this.toLong().humanReadable()
}
फिर आसानी से इस प्रकार उपयोग किया जाता है:
println(1999549L.humanReadable())
println(someInt.humanReadable())
नमूना जावा 7+ पथ वर्ग का विस्तार
एक्सटेंशन विधियों के लिए एक सामान्य उपयोग का मामला मौजूदा एपीआई में सुधार करना है। यहाँ exist
, notExists
और deleteRecursively
करने के उदाहरण जावा 7+ Path
क्लास में:
fun Path.exists(): Boolean = Files.exists(this)
fun Path.notExists(): Boolean = !this.exists()
fun Path.deleteRecursively(): Boolean = this.toFile().deleteRecursively()
जिसे अब इस उदाहरण में आमंत्रित किया जा सकता है:
val dir = Paths.get(dirName)
if (dir.exists()) dir.deleteRecursively()
पठनीयता में सुधार के लिए विस्तार कार्यों का उपयोग करना
कोटलिन में आप कोड लिख सकते हैं जैसे:
val x: Path = Paths.get("dirName").apply {
if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}
लेकिन apply
का उपयोग आपके इरादे के रूप में स्पष्ट नहीं है। कभी-कभी यह कार्रवाई को बदलने के लिए एक समान विस्तार समारोह बनाने के लिए स्पष्ट होता है और इसे और अधिक स्पष्ट करता है। इसे हाथ से बाहर निकलने की अनुमति नहीं दी जानी चाहिए, लेकिन सत्यापन जैसे बहुत ही सामान्य कार्यों के लिए:
infix inline fun <T> T.verifiedBy(verifyWith: (T) -> Unit): T {
verifyWith(this)
return this
}
infix inline fun <T: Any> T.verifiedWith(verifyWith: T.() -> Unit): T {
this.verifyWith()
return this
}
अब आप कोड को इस प्रकार लिख सकते हैं:
val x: Path = Paths.get("dirName") verifiedWith {
if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}
जो अब लोगों को पता है कि लैम्ब्डा पैरामीटर के भीतर क्या उम्मीद है।
ध्यान दें कि प्रकार पैरामीटर T
के लिए verifiedBy
रूप में ही है T: Any?
इसका अर्थ है कि अशक्त प्रकार भी एक्सटेंशन के उस संस्करण का उपयोग करने में सक्षम होंगे। हालांकि verifiedWith
साथ गैर-अशक्त होना आवश्यक है।
एक आईएसओ स्वरूपित स्ट्रिंग प्रदान करने के लिए जावा 8 टेम्पोरल कक्षाओं का विस्तार नमूना
इस घोषणा के साथ:
fun Temporal.toIsoString(): String = DateTimeFormatter.ISO_INSTANT.format(this)
अब आप बस:
val dateAsString = someInstant.toIsoString()
साथी वस्तुओं को विस्तार कार्य (स्थैतिक कार्यों की उपस्थिति)
यदि आप एक वर्ग का विस्तार करना चाहते हैं, जैसे कि आप एक स्थिर कार्य हैं, उदाहरण के लिए कक्षा के लिए Something
स्थैतिक रूप से दिखने वाले फ़ंक्शन को fromString
, तो यह केवल तभी काम कर सकता है जब वर्ग में एक साथी वस्तु हो और विस्तार कार्य को साथी ऑब्जेक्ट पर घोषित किया गया हो :
class Something {
companion object {}
}
class SomethingElse {
}
fun Something.Companion.fromString(s: String): Something = ...
fun SomethingElse.fromString(s: String): SomethingElse = ...
fun main(args: Array<String>) {
Something.fromString("") //valid as extension function declared upon the
//companion object
SomethingElse().fromString("") //valid, function invoked on instance not
//statically
SomethingElse.fromString("") //invalid
}
आलसी एक्सटेंशन प्रॉपर्टी वर्कअराउंड
मान लें कि आप एक एक्सटेंशन प्रॉपर्टी बनाना चाहते हैं जो गणना करना महंगा हो। इस प्रकार आप आलसी संपत्ति के प्रतिनिधि का उपयोग करके और वर्तमान उदाहरण ( this
) का उल्लेख करके गणना को कैश करना चाहते हैं, लेकिन आप ऐसा नहीं कर सकते, जैसा कि कोटलिन केटी -9686 और केटी -13053 के मुद्दों में बताया गया है। हालाँकि, यहां एक आधिकारिक समाधान प्रदान किया गया है ।
उदाहरण में, विस्तार गुण color
। यह एक स्पष्ट colorCache
का उपयोग करता है जिसे this
साथ प्रयोग किया जा सकता है क्योंकि कोई lazy
आवश्यक नहीं है:
class KColor(val value: Int)
private val colorCache = mutableMapOf<KColor, Color>()
val KColor.color: Color
get() = colorCache.getOrPut(this) { Color(value, true) }
आसान संदर्भ के लिए एक्सटेंशन कोड से देखें
जब आप विचार बनाते हैं, तो आप संदर्भ व्यू के लिए एक्सटेंशन का उपयोग कर सकते हैं, कोई और बॉयलरप्लेट नहीं।
मूल विचार Anko लाइब्रेरी द्वारा है
एक्सटेंशन
inline fun <reified T : View> View.find(id: Int): T = findViewById(id) as T
inline fun <reified T : View> Activity.find(id: Int): T = findViewById(id) as T
inline fun <reified T : View> Fragment.find(id: Int): T = view?.findViewById(id) as T
inline fun <reified T : View> RecyclerView.ViewHolder.find(id: Int): T = itemView?.findViewById(id) as T
inline fun <reified T : View> View.findOptional(id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Activity.findOptional(id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Fragment.findOptional(id: Int): T? = view?.findViewById(id) as? T
inline fun <reified T : View> RecyclerView.ViewHolder.findOptional(id: Int): T? = itemView?.findViewById(id) as? T
प्रयोग
val yourButton by lazy { find<Button>(R.id.yourButtonId) }
val yourText by lazy { find<TextView>(R.id.yourTextId) }
val yourEdittextOptional by lazy { findOptional<EditText>(R.id.yourOptionEdittextId) }