ठीक है, मैं समझ रहा टिप्पणियां सिर्फ पोस्टिंग के बजाय उस पर मेरी ले होनी चाहिए,। क्षमा करें, यह लंबा होगा, यदि आप चाहते हैं कि टीएलडीआर अंत तक छोड़ जाए।
के रूप में रान्डेल शुल्ज ने कहा, यहां _
एक अस्तित्व प्रकार के लिए एक आशुलिपि है। अर्थात्,
class Foo[T <: List[_]]
के लिए
class Foo[T <: List[Z] forSome { type Z }]
नोट एक आशुलिपि है कि क्या रान्डेल Shulz के जवाब का उल्लेख है के विपरीत (पूर्ण प्रकटीकरण: मैं गलत यह भी इस पोस्ट के लिए किसी पुराने संस्करण में मिला है, जेस्पर Nordenberg करने के लिए धन्यवाद
0:
class Foo[T <: List[Z]] forSome { type Z }
और न ही यह रूप में एक ही है: यह उनका कहना है) यह एक ही नहीं के रूप में के लिए
सावधान रहें, इसे गलत करना आसान है (मेरे पहले के गोफ शो के रूप में): रैंडल शुल्ज़ के जवाब के संदर्भ में आलेख के लेखक ने इसे गलत पाया (टिप्पणियां देखें), और बाद में इसे ठीक कर दिया। इस आलेख के साथ मेरी मुख्य समस्या यह है कि उदाहरण में दिखाया गया है कि अस्तित्व का उपयोग हमें टाइपिंग समस्या से बचाने के लिए है, लेकिन ऐसा नहीं है। कोड जांचें, और compileAndRun(helloWorldVM("Test"))
या compileAndRun(intVM(42))
संकलित करने का प्रयास करें। हां, संकलन नहीं करता है। बस compileAndRun
A
में जेनेरिक कोड संकलित करेगा, और यह बहुत आसान होगा। संक्षेप में, शायद अस्तित्व के बारे में जानने के लिए यह सबसे अच्छा लेख नहीं है और वे किसके लिए अच्छे हैं (लेखक स्वयं एक टिप्पणी में स्वीकार करते हैं कि लेख "को साफ करने की आवश्यकता है")।
तो मैं इस आलेख को पढ़ने की सिफारिश करता हूं: http://www.artima.com/scalazine/articles/scalas_type_system.html, विशेष रूप से "मौजूदा प्रकार" और "जावा और स्कैला में भिन्नता" नामक अनुभाग।
इस लेख से आपको जो महत्वपूर्ण बिंदु मिलना चाहिए वह यह है कि गैर-कॉन्वेंट प्रकारों से निपटने के दौरान अस्तित्व उपयोगी हैं (जेनेरिक जावा वर्गों से निपटने में सक्षम होने के अलावा)। यहां एक उदाहरण है।
case class Greets[T](private val name: T) {
def hello() { println("Hello " + name) }
def getName: T = name
}
इस वर्ग के सामान्य है (ध्यान दें यह भी कहा कि अपरिवर्तनीय है), लेकिन हम देख सकते हैं कि hello
वास्तव में (getName
के विपरीत) प्रकार पैरामीटर का उपयोग नहीं करते हैं, इसलिए यदि मैं Greets
मैं का एक उदाहरण मिलता है हमेशा इसे कॉल करने में सक्षम होना चाहिए, जो भी T
है। मैं एक विधि है कि एक Greets
उदाहरण लेता है परिभाषित करना चाहते हैं और सिर्फ अपने hello
प्रणाली को बुलाती है, तो मैं इस कोशिश कर सकते:
def sayHi1(g: Greets[T]) { g.hello() } // Does not compile
पर्याप्त बेशक, इस संकलन नहीं करता है, के रूप में T
कहीं नहीं यहाँ से बाहर आता है।
ठीक तो, विधि सामान्य बनाते हैं:
def sayHi2[T](g: Greets[T]) { g.hello() }
sayHi2(Greets("John"))
sayHi2(Greets('Jack))
बढ़िया है, यह काम करता है। हम यहां अस्तित्व का भी उपयोग कर सकते हैं:
def sayHi3(g: Greets[_]) { g.hello() }
sayHi3(Greets("John"))
sayHi3(Greets('Jack))
भी काम करता है। तो सब कुछ, अस्तित्व (जैसे sayHi3
में) टाइप पैरामीटर (जैसे sayHi2
) का उपयोग करने से यहां कोई वास्तविक लाभ नहीं है।
हालांकि, अगर Greets
किसी अन्य जेनेरिक वर्ग में टाइप पैरामीटर के रूप में दिखाई देता है तो यह परिवर्तन होता है। उदाहरण के लिए कहें कि हम एक सूची में Greets
(विभिन्न T
के साथ) के कई उदाहरणों को स्टोर करना चाहते हैं। यह कोशिश करते हैं:
val greets1: Greets[String] = Greets("John")
val greets2: Greets[Symbol] = Greets('Jack)
val greetsList1: List[Greets[Any]] = List(greets1, greets2) // Does not compile
अंतिम पंक्ति संकलन नहीं है क्योंकि Greets
अपरिवर्तनीय है, तो एक Greets[String]
और Greets[Symbol]
एक Greets[Any]
भी String
और Symbol
हालांकि दोनों फैली Any
के रूप में नहीं माना जा सकता।
val greetsList2: List[Greets[_]] = List(greets1, greets2) // Compiles fine, yeah
यह ठीक संकलित, अपेक्षा के अनुरूप है, और आप कर सकते हैं::
ठीक है, के आशुलिपि संकेतन _
का उपयोग कर एक अस्तित्व के साथ प्रयास करें, चलो
greetsSet foreach (_.hello)
अब, यही कारण है याद हमारे पास पहली जगह में एक प्रकार की जांच समस्या थी क्योंकि Greets
invariant है। यदि इसे एक कॉन्वेंरिएंट क्लास (class Greets[+T]
) में बदल दिया गया था तो सब कुछ बॉक्स से बाहर काम करता और हमें कभी भी अस्तित्व की आवश्यकता नहीं होती।
तो योग करने के लिए, existentials सामान्य अपरिवर्तनीय वर्गों से निपटने के लिए उपयोगी होते हैं, लेकिन अगर सामान्य वर्ग एक और सामान्य वर्ग के लिए एक प्रकार पैरामीटर के रूप में प्रकट करने के लिए की जरूरत नहीं है, संभावना है कि आप की जरूरत नहीं है कर रहे हैं existentials और बस अपने विधि करने के लिए एक प्रकार पैरामीटर जोड़ने के बारे में
class Foo[T <: List[_]]
क्योंकि List
covariant है
काम करेंगे, अपने विशिष्ट प्रश्न पर वापस आते हैं (पिछले पर, मुझे पता है!) अब, यह सभी उद्देश्यों के लिए है और purp ओएसई जैसा कह रहा है:
class Foo[T <: List[Any]]
तो इस मामले में, या तो नोटेशन का उपयोग करना वास्तव में शैली का मामला है।
हालांकि, अगर आप Set
साथ List
की जगह, चीजों को बदलना:
class Foo[T <: Set[_]]
Set
अपरिवर्तनीय है और इस तरह हम अपना उदाहरण से Greets
वर्ग के साथ के रूप में एक ही स्थिति में हैं। इस प्रकार उपरोक्त वास्तव में
class Foo[T <: Set[Any]]
एक प्रकार को रोकने के लिए '<: कोई भी' कभी भी कुछ भी नहीं बदलता है। स्कैला में हर प्रकार '<: कोई भी 'है। –