6

मेरे पास एक डिज़ाइन पैटर्न है जहां ऑब्जेक्ट जेनरेटर (मॉर्सल जेनरेटर और उसके बच्चे) हैं, जिनमें से कोई भी उदाहरण हमेशा एक ही सटीक प्रकार की ऑब्जेक्ट उत्पन्न करता है (मोर्सल्स और उसके बच्चे), लेकिन टाइप चेकर मुझे इन उत्पन्न वस्तुओं में से दो या अधिक पर कोई भी संचालन करने नहीं देगा, मानते हैं कि वे अलग हो सकते हैं।स्कैला प्रकार अनुमान इस बात को ध्यान में रखता है कि ये प्रकार समान हैं, जो भी

मैं इस प्रकार के प्रकार चेकर को कैसे प्राप्त करूं?

trait Morsel 
{ 
    type M <: Morsel 
    def calories : Float 
    def + (v : M) : M 
} 

trait MorselGenerator 
{ 
    type Mg <: Morsel 
    def generateMorsel : Mg 
} 

class HotDog(c : Float, l : Float, w : Float) extends Morsel 
{ 
    type M = HotDog 
    val calories : Float = c 
    val length : Float = l  
    val width : Float = w 
    def + (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width) 
} 

class HotDogGenerator extends MorselGenerator 
{ 
    type Mg = HotDog 
    def generateMorsel : HotDog = new HotDog(500.0f, 3.14159f, 445.1f) 
} 

object Factory 
{ 
    def main (args : Array[String]) 
    { 
     val hdGen = new HotDogGenerator() 
     println(eatTwo(hdGen)) 
    } 

    def eatTwo (mGen : MorselGenerator) 
    { 
     val v0 : mGen.Mg = mGen.generateMorsel 
     val v1 : mGen.Mg = mGen.generateMorsel 
     v0 + v1       /// ERROR HERE 
    } 
} 

संकलक निम्नलिखित संकलन त्रुटि

Generator.scala:43: error: type mismatch; 
found : v1.type (with underlying type mGen.Mg) 
required: v0.M 
     v0 + v1       /// ERROR HERE 
     ^one error found 
उत्पन्न


अद्यतन

यहाँ सी ++ कोड कम या ज्यादा मैं क्या कर रहा हूँ के बराबर है कि है। ध्यान दें कि खाने दो कार्य पूरी तरह से polymorphic है और विशिष्ट व्युत्पन्न प्रकार के मोर्सेल या मोर्सेल जेनरेटर का कोई संदर्भ नहीं देता है।

#include <stdlib.h> 
#include <stdio.h> 

template <class M> class Morsel 
{ 
public: 
    Morsel(float c) : calories(c) {} 
    float calories; 
    virtual M operator + (const M& rhs) const = 0; 
}; 

template <class M> class MorselGenerator 
{ 
public: 
    virtual M * generateMorsel() const = 0; 
}; 

class HotDog : public Morsel<HotDog> 
{ 
public: 
    HotDog(float c, float l, float w) : Morsel<HotDog>(c), length(l), width(w) {} 
    float length, width; 

    HotDog operator + (const HotDog& rhs) const 
    { return HotDog(calories+rhs.calories, length+rhs.length, width+rhs.width); } 
}; 

class HotDogGenerator : public MorselGenerator<HotDog> 
{ 
    HotDog * generateMorsel() const { return new HotDog(500.0f, 3.14159f, 445.1f); } 
}; 

/////////////////////////////////////////////// 

template <class MorselType> float eatTwo (const MorselGenerator<MorselType>& mGen) 
{ 
    MorselType * m0 = mGen.generateMorsel(); 
    MorselType * m1 = mGen.generateMorsel(); 
    float sum = ((*m0) + (*m1)).calories; 
    delete m0; delete m1; 
    return sum; 
} 

int main() 
{ 
    MorselGenerator<HotDog> * morselStream = new HotDogGenerator(); 
    printf("Calories Ingested: %.2f\n", eatTwo(*morselStream)); 
    delete morselStream; 
} 
+0

शायद यह मदद करेगा: http://stackoverflow.com/questions/9198562/scala-self-type-and-this-type-in-collections-issue – tuxSlayer

उत्तर

2

यह सिर्फ कैसे सदस्य प्रकार स्काला में काम करते हैं: वे केवल बराबर माना जाता है जब बाहरी वस्तुओं में एक ही (संकलक होने के लिए करने के लिए जाना जाता है) कर रहे हैं।

trait Morsel[M <: Morsel] 
{ 
    def calories : Float 
    def + (v : M) : M 
} 

trait MorselGenerator[Mg <: Morsel] 
{ 
    def generateMorsel : Mg 
} 

... 
+0

अच्छा, यह वास्तव में काम नहीं कर रहा है।सबसे पहले, हमें इस प्रकार के लक्षणों को परिभाषित करना होगा: 'विशेषता मोर्सेल [एमजी <: मोर्सेल [एमजी]]' आदि जो विचित्र रूप से परिपत्र प्रतीत होता है। इस डिजाइन के साथ-साथ, जब मैं दो मोर्सल्स (हॉटडॉग) जोड़ने की कोशिश करता हूं तो संकलक पहले से कहीं ज्यादा भ्रमित होता है। – Fooberman

+1

यह 'कक्षा हॉटडॉग ... {प्रकार एम = हॉटडॉग ...} 'से अधिक परिपत्र नहीं है। Http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern देखें –

4

त्रुटि, समझ में आता है क्योंकि विधि जहां संकलन विफल रहता है, संकलक गारंटी नहीं दे सकते कि आप एक hotdog के लिए आइस क्रीम जोड़ने नहीं कर रहे हैं: एक विकल्प के बजाय प्रकार पैरामीटर का प्रयोग है। एक नया

hotdog में

+ विधि समस्या को हाइलाइट करने में मदद करता है, और वास्तव में आप विधि पर हावी नहीं है, बल्कि आपके द्वारा जोड़ी गई एक: के लिए

def + (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width) 

कि स्पष्टत प्रकार की जरूरत है जोड़ा जा रहा है "इस" के समान प्रकार।

निवाला जैसे परिभाषित करें, और समस्या लगभग हल किया जाता है:

override def + (v : Morsel): Morsel = v match { 
    case hd: HotDog => new HotDog(hd.calories + calories, hd.length + length, hd.width + width) 
    case x => throw new IllegalArgumentException("eurgh!") 
} 

मुझे यकीन है कि अगर आप प्राप्त कर सकते हैं नहीं कर रहा हूँ:

trait Morsel { 
    def calories : Float 
    def + (v : Morsel) : Morsel 
} 

अंतिम भाग ठीक से + विधि ओवरराइड करने के लिए है आपके द्वारा प्रदान किए गए फॉर्म में कोड का उपयोग करके, आइसक्रीम और हॉटडॉग जोड़ने से रोकने के लिए कंपाइलर।

0

संभव समाधान में से एक (i add यहाँ के साथ + बदल दिया है अंत में, +(String, String) से दूर रहने की, + ठीक है):

trait Morsel[M <: Morsel[M]] { /// this 
    this: M =>      /// and this make the trick 
    def calories : Float 
    def add(v : M) : M 
} 

trait MorselGenerator[Mg <: Morsel[Mg]] 
{ 
    def generateMorsel : Mg 
} 

class HotDog(c : Float, l : Float, w : Float) extends Morsel[HotDog] 
{ 
    val calories : Float = c 
    val length : Float = l  
    val width : Float = w 
    override def add (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width) 
} 

class HotDogGenerator extends MorselGenerator[HotDog] 
{ 
    def generateMorsel : HotDog = new HotDog(500.0f, 3.14159f, 445.1f) 
} 

object Factory extends App 
{ 
    def eatTwo[M <: Morsel[M]](mGen : MorselGenerator[M]) = { 
    val v0 = mGen.generateMorsel 
    val v1 = mGen.generateMorsel 
    v0 add v1  
    } 

    val hdGen = new HotDogGenerator() 
    println(eatTwo(hdGen)) 
} 
0

और मामूली अन्य संस्करण:

trait MorselGenerator { 
    type M <: Morsel 

    trait Morsel { this: M => 
    def calories : Float 
    def add (v : M) : M 
    }  

    def generateMorsel : M 
} 

class HotDogGenerator extends MorselGenerator 
{ 
    type M = HotDog 

    class HotDog(c : Float, l : Float, w : Float) extends Morsel { 
    val calories : Float = c 
    val length : Float = l  
    val width : Float = w 
    def add (v : HotDog) : HotDog = new HotDog(v.calories + calories, v.length + length, v.width + width) 
    } 

    def generateMorsel: HotDog = new HotDog(500.0f, 3.14159f, 445.1f) 
} 

object Factory extends App 
{ 
    val hdGen = new HotDogGenerator() 

    hdGen.generateMorsel add hdGen.generateMorsel add hdGen.generateMorsel 

    produceDouble(hdGen) 

    def produceDouble(gen: MorselGenerator): MorselGenerator#Morsel = { 
    gen.generateMorsel add gen.generateMorsel 
    } 
} 

शायद कम उपयोगी है, लेकिन यह दिखा सकता है कि समस्या कहां है। स्कैला में "पथ निर्भर" प्रकार हैं, इसलिए obj1.Type और obj2.Type विभिन्न प्रकार हैं भले ही obj1.type == obj2.type।

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