कोटलिन में स्थैतिक विस्तार के तरीके


142

आप कोटलिन में एक स्थिर विस्तार विधि को कैसे परिभाषित करते हैं? क्या यह भी संभव है? मेरे पास वर्तमान में एक विस्तार विधि है जैसा कि नीचे दिखाया गया है।

public fun Uber.doMagic(context: Context) {
    // ...
}

एक उदाहरण पर उपरोक्त विस्तार को लागू किया जा सकता है।

uberInstance.doMagic(context) // Instance method

लेकिन मैं इसे कैसे बना सकता हूं जैसे नीचे दिखाया गया है।

Uber.doMagic(context)         // Static or class method

1
"स्थैतिक विस्तार विधि" से आपका क्या अभिप्राय है?
एंड्री ब्रेस्लाव

3
एक विधि जिसे मैं उदाहरण के बिना कॉल कर सकता हूं, लेकिन अभी भी कक्षा का एक विस्तार है। (रेगुलर जावा स्टैटिक मेथड्स)
रघुनाथ जवाहर

मुझे लगता है कि यह कोटलिन एक्सटेंशन के अच्छे प्रश्न का अभीष्ट उपयोग नहीं हो सकता है , मैंने सी # अवधारणा को एक्सट्रपलेट करने की कोशिश करते हुए एक ही बात के बारे में सोचा। लेकिन अभ्यास में उपयोग काफी समान है। कोटलिन एक्सटेंशन, जबकि वे सांख्यिकीय रूप से भेजे जाने का दावा करते हैं, वे गतिशील रूप से "संलग्न" महसूस करते हैं, अगर ऐसी कोई चीज़ है, या उदाहरण के लिए देर से बँधा हुआ है। अगर मैं गलत नहीं हूँ ... या शायद मुझे यह पूरी तरह गलत लगा :)
Dan

7
वर्तमान में आप एक विस्तार विधि नहीं लिख सकते हैं जिसे वर्ग के उदाहरण के विपरीत वर्ग नाम पर बुलाया जाएगा। वास्तव में, एक्सटेंशन फ़ंक्शन एक रिसीवर पैरामीटर लेता है जो एक उदाहरण है, इसलिए इस हिस्से को छोड़ने का कोई तरीका नहीं है। दूसरी ओर, हम क्लास ऑब्जेक्ट्स के लिए एक्सटेंशन लिखने के एक तरीके पर काम कर रहे हैं, ताकि आप इसे क्लास के नाम से बुलाएं, लेकिन रिसीवर के पास क्लास ऑब्जेक्ट का प्रकार है
एंड्री ब्रेस्लेव

@AndreyBreslav क्या आप हमें अपडेट कर सकते हैं कि क्या स्थैतिक विस्तार कार्यों की अनुमति होगी? मुझे भी याद आ रही है।
लार्स ब्लमबर्ग

जवाबों:


143

प्राप्त करने के लिए Uber.doMagic(context), आप साथी ऑब्जेक्ट के लिए एक एक्सटेंशन लिख सकते हैं Uber(साथी ऑब्जेक्ट घोषणा आवश्यक है):

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }

79
यह अच्छा है लेकिन क्या होगा अगर यह एक जावा वर्ग या एक साथी के बिना एक वर्ग है?
जिरे

31
@ ऐसे मामलों के लिए,
कोटलिन

2
यदि आपके डोमेन तर्क के लिए यह आवश्यक है (खाली डेटा वर्गों के साथ संयोजन के रूप में वर्तमान में मेरा काम करता है), तो मैं डिफ़ॉल्ट मानों के साथ JVM फ्रेमवर्क कक्षाओं को विस्तारित करने में एक usecase देख सकता हूं, जैसे String.DEFAULT, या Int.DEFAULT।
स्टेफेन फंक

36
यह केवल तब तक काम करता है जब तक उबर एक कोटलिन वर्ग है। यह अच्छा होगा कि जावा कक्षाओं के साथ
स्टेटिक

6
यह अभी भी संभव नहीं है जैसा कि आप यहां देख सकते हैं: youtrack.jetbrains.com/issue/KT-11968 यहां एक संबंधित SO थ्रेड है: stackoverflow.com/questions/33911457/…
narko

12

यह आधिकारिक दस्तावेज कहता है:

कोटलिन पैकेज स्तर के कार्यों के लिए स्थैतिक तरीके उत्पन्न करता है। यदि आप उन कार्यों को @JvmStatic के रूप में एनोटेट करते हैं, तो कोटलिन नामित वस्तुओं या साथी वस्तुओं में परिभाषित कार्यों के लिए स्थिर तरीके भी उत्पन्न कर सकते हैं। उदाहरण के लिए:

कोटलिन स्थिर तरीके

class C {
  companion object {
    @JvmStatic fun foo() {}
    fun bar() {}
  }
}

अब, foo () जावा में स्थिर है, जबकि बार () नहीं है:

C.foo(); // works fine
C.bar(); // error: not a static method

8

मेरे पास वास्तव में यह सटीक प्रश्न 30 मिनट पहले था, इसलिए मैंने चारों ओर खुदाई शुरू कर दी और इसके लिए कोई समाधान या समाधान नहीं खोज सका, लेकिन खोज करते समय मुझे कोटलिंग्लांग वेबसाइट पर यह खंड मिला जो बताता है कि:

ध्यान दें कि एक्सटेंशन को एक अशक्त रिसीवर प्रकार के साथ परिभाषित किया जा सकता है। इस तरह के एक्सटेंशन को ऑब्जेक्ट वैरिएबल पर भी बुलाया जा सकता है, भले ही इसका मूल्य शून्य हो।

तो फिर मुझे कभी भी सबसे अजीब विचार आया, क्यों एक अशक्त रिसीवर (वास्तव में उस रिसीवर का उपयोग किए बिना) के साथ एक एक्सटेंशन फ़ंक्शन को परिभाषित नहीं किया और फिर इसे एक अशक्त वस्तु पर कॉल किया! तो मैंने कोशिश की, और यह बहुत अच्छी तरह से काम किया, लेकिन यह बहुत बदसूरत लग रहा था। यह इस तरह था:

(null as Type?).staticFunction(param1, param2)

इसलिए मैं चारों ओर चला गया कि रिसीवर प्रकार की मेरी एक्सटेंशन फ़ाइल में एक वैल बनाकर, जिसमें शून्य का मान था और फिर इसे मेरे अन्य वर्ग में उपयोग करें। इसलिए, एक उदाहरण के रूप में, यहां बताया गया है कि मैंने Navigationएंड्रॉइड में क्लास के लिए "स्टैटिक" एक्सटेंशन फ़ंक्शन कैसे लागू किया है: मेरे नेवीगेशन एक्सटेंशन में।

val SNavigation: Navigation? = null
fun Navigation?.createNavigateOnClickListener(@IdRes resId: Int, args: Bundle? = null, navOptions: NavOptions? = null,
                                                navigationExtras: Navigator.Extras? = null) : (View) -> Unit {
    //This is just implementation details, don't worry too much about them, just focus on the Navigation? part in the method declaration
    return { view: View -> view.navigate(resId, args, navOptions, navigationExtras) }
}

इसका उपयोग करने वाले कोड में:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

जाहिर है, यह एक वर्ग का नाम नहीं है, यह क्लास प्रकार का एक चर है जिसमें एक शून्य मान है। यह स्पष्ट रूप से विस्तार निर्माता की ओर से बदसूरत है (क्योंकि उन्हें चर बनाना है) और डेवलपर की ओर (क्योंकि उन्हें STypeवास्तविक वर्ग नाम के बजाय प्रारूप का उपयोग करना है ), लेकिन यह निकटतम है जिसे अभी प्राप्त किया जा सकता है वास्तविक स्थिर कार्यों की तुलना में। उम्मीद है, कोटलिन भाषा निर्माता इस मुद्दे पर प्रतिक्रिया देंगे और भाषा में उस विशेषता को जोड़ देंगे ।


2
हैकी यह है लेकिन चतुर शांत भी। यह सवाल का सबसे व्यावहारिक जवाब है। फर्स्ट क्लास एक्सटेंशन प्रदान करने के लिए कोटलिन का यह सबसे अच्छा काम कर सकता है, इसलिए IMO, आप अपनी अमानवीयताओं से निपटने के लिए सर्वश्रेष्ठ-यू-विल समाधानों का उपयोग कर सकते हैं। अच्छा लगा।
ट्रैविस ग्रिग्स 5

5

आप साथी ऑब्जेक्ट का उपयोग करके एक स्थिर विधि बना सकते हैं जैसे:

class Foo {
    // ...
    companion object {
        public fun bar() {
            // do anything
        }
    }
}

और फिर आप इसे कॉल कर सकते हैं जैसे:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}

मेरा मानना ​​है कि वास्तव में स्थिर नहीं है। साथी ऑब्जेक्ट आपको क्लास नाम का उपयोग करने के लिए कॉल करने की अनुमति देते हैं, लेकिन फिर भी क्लास के एक उदाहरण का उपयोग करते हैं। साथ ही, सवाल स्थैतिक विस्तार कार्यों के बारे में था, न केवल स्थैतिक कार्यों के बारे में। हालांकि स्थिर कार्य करने के लिए आप platformStaticएनोटेशन का उपयोग कर सकते हैं ।
रघुनाथ जवाहर

1
platformStaticJvmStaticवर्तमान कोटलिन में नाम बदल दिया गया था ।
जैसन मिनार्ड

0

इस लिंक को देखने के लिए आपको याद करते हैं । जैसा कि आप वहां देख सकते हैं, आपको बस पैकेज के शीर्ष-स्तर पर विधि घोषित करनी चाहिए (फाइल):

package strings
public fun joinToString(...): String { ... }

यह बराबर है

package strings;

public class JoinKt {
    public static String joinToString(...) { ... }
}

स्थिरांक के साथ सब कुछ समान है। यह घोषणा

val UNIX_LINE_SEPARATOR = "\n"

के बराबर है

public static final String UNIX_LINE_SEPARATOR = "\n";

-3

मैं भी कोटलिन में स्थैतिक विस्तार विधियों को जोड़ने की संभावना रखने का काफी शौकीन हूं। अभी के लिए एक वर्कअराउंड के रूप में मैं उन सभी में एक स्टैटिक एक्सटेंशन विधि का उपयोग करने के बजाय कई वर्गों में एक्सेंशन विधि जोड़ रहा हूं।

class Util    

fun Util.isDeviceOnline(context: Context): Boolean {
    val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connMgr.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

fun Activity.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
fun OkHttpClient.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }

2
मूल प्रश्न यह था कि एक स्थिर विधि के साथ एक javaclass कैसे बढ़ाया जा सकता है । आपके मामले में, इसका मतलब है कि शाब्दिक रूप से कॉल करने में सक्षम Activity.isDeviceOnline(...)होने का कोई उदाहरण नहीं है Activity
फेबियन ज़िन्द्ल

-4

कोटलिन में एक विस्तार विधि बनाने के लिए आपको एक कोटलिन फ़ाइल (क्लास नहीं) बनानी होगी, फिर फ़ाइल में अपना तरीका घोषित करें:

public fun String.toLowercase(){
    // **this** is the string object
}

जिस क्लास या फाइल पर आप काम कर रहे हैं, उसमें फंक्शन को इम्पोर्ट करें और उसका इस्तेमाल करें।


शीर्षक भी एक सवाल नहीं है
daniel.jbatiz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.