2011-12-16 12 views
15

समारोह संरचनात्मक प्रकार स्वीकार करता है, यह परिभाषित किया जा सकता है:स्कैला संरचनात्मक प्रकार पर कॉल विधि के प्रतिबिंब का उपयोग क्यों करता है?

def doTheThings(duck: { def walk; def quack }) { duck.quack } 

या

type DuckType = { def walk; def quack } 
def doTheThings(duck: DuckType) { duck.quack } 

उसके बाद, आप निम्नलिखित तरीके से कि समारोह का उपयोग कर सकते हैं:

class Dog { 
    def walk { println("Dog walk") } 
    def quack { println("Dog quacks") } 
} 

def main(args: Array[String]) { 
    doTheThings(new Dog); 
} 

आप डिकंपाइल हैं (जावा में) मेरे उदाहरण के लिए स्केलैक द्वारा उत्पन्न कक्षाएं, आप देख सकते हैं कि doTheThings का तर्क Object और आईएम का प्रकार है plementation तर्क पर कॉल विधियों के प्रतिबिंब का उपयोग करता है (यानी। duck.quack)

मेरा प्रश्न है कि प्रतिबिंब क्यों? क्या प्रतिबिंब के बजाय अज्ञात और invokevirtual का उपयोग करना संभव नहीं है?

यहाँ अनुवाद करने के लिए (लागू) संरचनात्मक प्रकार कहता है मेरे उदाहरण के लिए तरीका है (जावा वाक्य रचना है, लेकिन बिंदु बाईटकोड है):

class DuckyDogTest { 
    interface DuckType { 
    void walk(); 
    void quack(); 
    } 

    static void doTheThing(DuckType d) { 
    d.quack(); 
    } 

    static class Dog { 
    public void walk() { System.out.println("Dog walk"); } 
    public void quack() { System.out.println("Dog quack"); } 
    } 

    public static void main(String[] args) { 
    final Dog d = new Dog(); 
    doTheThing(new DuckType() { 
     public final void walk() { d.walk(); } 
     public final void quack() { d.quack();} 
    }); 
    } 
} 

उत्तर

13

एक सरल प्रस्ताव पर विचार करें:

type T = { def quack(): Unit; def walk(): Unit } 
def f(a: T, b: T) = 
    if (a eq b) println("They are the same duck!") 
    else  println("Different ducks") 

f(x, x) // x is a duck 

यह आपके प्रस्ताव के तहत Different ducks प्रिंट करेगा। आप इसे और परिष्कृत कर सकते हैं, लेकिन आप प्रॉक्सी का उपयोग करके संदर्भित समानता को बरकरार नहीं रख सकते हैं।

टाइप क्लास पैटर्न का उपयोग करने के लिए एक संभावित समाधान होगा, लेकिन इसके लिए एक और पैरामीटर (भले ही अंतर्निहित) गुजरने की आवश्यकता होगी। फिर भी, यह तेज़ है। लेकिन यह ज्यादातर जावा की प्रतिबिंब गति की लापरवाही के कारण है। उम्मीद है कि, विधि हैंडल गति की समस्या के आसपास मिल जाएगा। दुर्भाग्यवश, स्कैला को कुछ समय के लिए जावा 5, 6 और 7 (जिसमें विधि हैंडल नहीं है) पर छोड़ने के लिए निर्धारित नहीं है ...

+0

मुझे अंतिम वाक्य नहीं मिलता है, क्या आप कृपया समझा सकते हैं? –

+0

@ ओम-नाम-नाम 'invokevirtual' JVM 1.5 और 1.6 पर मौजूद नहीं है, इसलिए स्कैला इस पर भरोसा नहीं कर सकता है। स्कैला 2.10 वास्तव में जेवीएम 1.5 को हटा देगा, लेकिन स्कैला केवल जेवीएम 1.7 पर मौजूद चीजों का लाभ उठा सकता है, लेकिन यह अभी भी कुछ समय पहले है। –

+0

@ डैनियल सी सोब्राल: मुझे लगता है कि आपकी पिछली टिप्पणी –

10

संरचनात्मक प्रकार पर आपके प्रॉक्सी ऑब्जेक्ट कार्यान्वयन विधियों के अतिरिक्त, यह भी होगा किसी भी (बराबर, हैशकोड, टूस्ट्रिंग, isInstanceOf, asInstanceOf) और AnyRef (getClass, प्रतीक्षा, अधिसूचना, सूचित करें, और सिंक्रनाइज़) पर सभी विधियों के उचित पास-थ्रू कार्यान्वयन की आवश्यकता है। हालांकि इनमें से कुछ सीधा होगा, कुछ सही होने के लिए लगभग असंभव होगा। विशेष रूप से, सूचीबद्ध सभी विधियां AnyRef (जावा संगतता और सुरक्षा के लिए) पर "अंतिम" हैं और इसलिए आपके प्रॉक्सी ऑब्जेक्ट द्वारा ठीक से कार्यान्वित नहीं किया जा सका।

+1

@ Daniel C.सोब्राल और डेव ग्रिफिथ: आपके दोनों उत्तर स्वीकार्य हैं। तो मुझे औपचारिक रूप से स्वीकार करने के लिए एक सिक्का टॉस करना पड़ा। –

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

  • कोई संबंधित समस्या नहीं^_^