जावा बैकग्राउंड से आने वाली स्विफ्ट के साथ खेलते हुए, आप क्लास की बजाय स्ट्रक्चर क्यों चुनना चाहेंगे? लगता है कि वे एक ही चीज़ हैं, जिसमें एक संरचना कम कार्यक्षमता प्रदान करती है। फिर इसे क्यों चुना?
जावा बैकग्राउंड से आने वाली स्विफ्ट के साथ खेलते हुए, आप क्लास की बजाय स्ट्रक्चर क्यों चुनना चाहेंगे? लगता है कि वे एक ही चीज़ हैं, जिसमें एक संरचना कम कार्यक्षमता प्रदान करती है। फिर इसे क्यों चुना?
जवाबों:
बहुत लोकप्रिय WWDC 2015 टॉक प्रोटोकॉल ओरिएंटेड प्रोग्रामिंग इन स्विफ्ट ( वीडियो , ट्रांसक्रिप्ट ) के अनुसार, स्विफ्ट कई विशेषताओं को प्रदान करता है जो कई परिस्थितियों में कक्षाओं की तुलना में बेहतर बनाते हैं।
संरचनाएं बेहतर होती हैं यदि वे अपेक्षाकृत छोटे और मैथुन योग्य हों क्योंकि नकल करना उसी तरह से कई संदर्भों की तुलना में सुरक्षित होता है जैसे कि कक्षाओं के साथ होता है। यह विशेष रूप से महत्वपूर्ण है जब एक चर के आसपास से गुजर रहा है कई वर्गों और / या एक बहुआयामी वातावरण में। यदि आप हमेशा अपने चर की एक प्रति अन्य स्थानों पर भेज सकते हैं, तो आपको कभी भी इस बात की चिंता नहीं करनी चाहिए कि आपके चर का मूल्य आपके नीचे बदल रहा है।
स्ट्रक्चर्स के साथ, एक चर के एक उदाहरण को एक्सेस / संशोधित करने के लिए मेमोरी लीक या मल्टीपल थ्रेड रेसिंग के बारे में चिंता करने की बहुत कम आवश्यकता होती है। (अधिक तकनीकी रूप से दिमाग के लिए, इसका अपवाद तब होता है जब किसी बंद के अंदर एक संरचना को कैप्चर करना क्योंकि तब यह वास्तव में उदाहरण के संदर्भ को कैप्चर कर रहा है जब तक कि आप स्पष्ट रूप से इसे कॉपी करने के लिए स्पष्ट रूप से चिह्नित नहीं करते हैं।
कक्षाएं भी फूला हुआ हो सकती हैं क्योंकि एक वर्ग केवल एक ही सुपरक्लास से विरासत में मिल सकता है। यह हमें बहुत सी अलग-अलग क्षमताओं को बनाने के लिए प्रोत्साहित करता है जो कई अलग-अलग क्षमताओं को शामिल करती हैं जो केवल शिथिल रूप से संबंधित हैं। प्रोटोकॉल का उपयोग करना, विशेष रूप से प्रोटोकॉल एक्सटेंशन के साथ जहां आप प्रोटोकॉल को कार्यान्वयन प्रदान कर सकते हैं, आपको इस प्रकार के व्यवहार को प्राप्त करने के लिए कक्षाओं की आवश्यकता को समाप्त करने की अनुमति देता है।
इन परिदृश्यों पर बात की जाती है जहाँ कक्षाएं पसंद की जाती हैं:
- उदाहरणों की नकल या तुलना करने का कोई मतलब नहीं है (उदाहरण के लिए, विंडो)
- उदाहरण जीवनकाल बाहरी प्रभावों से जुड़ा होता है (जैसे, TemporaryFile)
- उदाहरण केवल "सिंक" हैं - केवल बाहरी राज्य के लिए लेखन सामग्री (जैसे CGCONtext)
इसका तात्पर्य यह है कि संरचनाएं डिफ़ॉल्ट होनी चाहिए और कक्षाएं कमबैक होनी चाहिए।
दूसरी ओर, स्विफ्ट प्रोग्रामिंग भाषा प्रलेखन कुछ विरोधाभासी है:
संरचना उदाहरण हमेशा मूल्य से पारित किए जाते हैं, और वर्ग उदाहरण हमेशा संदर्भ द्वारा पारित किए जाते हैं। इसका मतलब है कि वे विभिन्न प्रकार के कार्यों के अनुकूल हैं। जब आप किसी प्रोजेक्ट के लिए आवश्यक डेटा कंस्ट्रक्शंस और कार्यक्षमता पर विचार करते हैं, तो तय करें कि प्रत्येक डेटा कंस्ट्रक्शन को एक वर्ग या एक संरचना के रूप में परिभाषित किया जाना चाहिए या नहीं।
सामान्य दिशानिर्देश के रूप में, एक संरचना बनाने पर विचार करें जब इनमें से एक या अधिक शर्तें लागू हों:
- संरचना का प्राथमिक उद्देश्य कुछ अपेक्षाकृत सरल डेटा मानों को संक्षिप्त करना है।
- यह उम्मीद करना उचित है कि जब आप असाइन या उस संरचना के एक उदाहरण के आसपास से गुजरते हैं, तो संदर्भित मानों को कॉपी किया जाएगा।
- संरचना द्वारा संग्रहीत कोई भी गुण स्वयं मूल्य प्रकार हैं, जिन्हें संदर्भित होने के बजाय कॉपी किए जाने की अपेक्षा की जाएगी।
- संरचना को किसी अन्य मौजूदा प्रकार से गुण या व्यवहार को इनहेरिट करने की आवश्यकता नहीं है।
संरचनाओं के लिए अच्छे उम्मीदवारों के उदाहरणों में शामिल हैं:
- एक ज्यामितीय आकार का आकार, शायद एक चौड़ाई संपत्ति और एक ऊंचाई संपत्ति, दोनों प्रकार के डबल को इनकैप्सुलेट कर रहा है।
- एक श्रृंखला के भीतर पर्वतमाला को संदर्भित करने का एक तरीका, शायद एक प्रारंभ संपत्ति और एक लंबी संपत्ति, दोनों प्रकार के इंट को अलग करना।
- एक 3 डी समन्वय प्रणाली में एक बिंदु, शायद एक्स, वाई और जेड गुण, टाइप डबल के प्रत्येक encapsulating।
अन्य सभी मामलों में, एक वर्ग को परिभाषित करें और संदर्भ द्वारा प्रबंधित और पारित होने के लिए उस वर्ग के उदाहरण बनाएं। व्यवहार में, इसका मतलब यह है कि अधिकांश कस्टम डेटा निर्माण कक्षाएं होनी चाहिए, न कि संरचनाएं।
यहां यह दावा किया जा रहा है कि हमें कक्षाओं का उपयोग करने के लिए डिफ़ॉल्ट होना चाहिए और केवल विशिष्ट परिस्थितियों में संरचनाओं का उपयोग करना चाहिए। अंततः, आपको मूल्य प्रकार बनाम संदर्भ प्रकारों के वास्तविक विश्व निहितार्थ को समझने की आवश्यकता है और फिर आप संरचना या कक्षाओं का उपयोग करने के बारे में एक सूचित निर्णय ले सकते हैं। इसके अलावा, ध्यान रखें कि ये अवधारणाएं हमेशा विकसित हो रही हैं और प्रोटोकॉल ओरिएंटेड प्रोग्रामिंग टॉक दिए जाने से पहले स्विफ्ट प्रोग्रामिंग लैंग्वेज डॉक्यूमेंटेशन लिखा गया था।
In practice, this means that most custom data constructs should be classes, not structures.
आप मुझे समझा सकते हैं कि, उसे पढ़ने के बाद, आपको लगता है कि अधिकांश डेटा सेट में संरचनाएं होनी चाहिए और कक्षाएं नहीं? उन्होंने नियमों का एक विशिष्ट सेट दिया जब कुछ को एक संरचना होना चाहिए और बहुत अधिक कहा जाना चाहिए "अन्य सभी परिदृश्य एक वर्ग बेहतर है।"
चूंकि स्टैक पर स्ट्रक्चर इंस्टेंसेस आवंटित किए जाते हैं, और क्लास इंस्टेंसेस को ढेर पर आवंटित किया जाता है, इसलिए स्ट्रक्चर्स कभी-कभी बहुत तेज हो सकते हैं।
हालाँकि, आपको हमेशा इसे स्वयं मापना चाहिए और अपने अनूठे उपयोग के मामले के आधार पर निर्णय लेना चाहिए।
निम्नलिखित उदाहरण पर विचार करें, जो Int
डेटा प्रकार का उपयोग करके रैपिंग की 2 रणनीतियों को प्रदर्शित करता है struct
और class
। मैं 10 दोहराया मूल्यों का उपयोग कर रहा हूं, वास्तविक दुनिया को बेहतर ढंग से प्रतिबिंबित करने के लिए हैं, जहां आपके पास कई क्षेत्र हैं।
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}
func + (x: Int10Class, y: Int10Class) -> Int10Class {
return IntClass(x.value + y.value)
}
func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return IntStruct(x.value + y.value)
}
प्रदर्शन का उपयोग करके मापा जाता है
// Measure Int10Class
measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}
// Measure Int10Struct
measure("struct (10 fields)") {
var y = Int10Struct(0)
for _ in 1...10000000 {
y = y + Int10Struct(1)
}
}
func measure(name: String, @noescape block: () -> ()) {
let t0 = CACurrentMediaTime()
block()
let dt = CACurrentMediaTime() - t0
print("\(name) -> \(dt)")
}
कोड https://github.com/knguyen2708/StructVsClassPerformance पर देखे जा सकते हैं
अद्यतन (27 मार्च 2018) :
Swift 4.0, Xcode 9.2 के रूप में, iPhone 6S, iOS 11.2.6 पर रिलीज़ रिलीज़ निर्माण, Swift कम्पाइलर सेटिंग है -O -whole-module-optimization
:
class
संस्करण 2.06 सेकंड लियाstruct
संस्करण 4.17e-08 सेकंड (50,000,000 बार तेज) लिया(मैं अब औसत कई रन नहीं बना सकता, क्योंकि संस्करण 5% से कम है)
नोट : अंतर पूरे मॉड्यूल अनुकूलन के बिना बहुत कम नाटकीय है। मुझे खुशी होगी अगर कोई यह बता सके कि झंडा वास्तव में क्या करता है।
अद्यतन (7 मई 2016) :
स्विफ्ट 2.2.1, एक्सकोड 7.3 के रूप में, आईफोन 6 एस, आईओएस 9.3.1 पर रिलीज बिल्ड चल रहा है, जो 5 रन से अधिक है, स्विफ्ट कंपाइलर सेटिंग है -O -whole-module-optimization
:
class
संस्करण 2.159942142s लियाstruct
संस्करण में 5.83E-08s (37,000,000 गुना तेज) लिया गयानोट : जैसा कि किसी ने उल्लेख किया है कि वास्तविक दुनिया के परिदृश्यों में, एक संरचना में 1 से अधिक क्षेत्र होने की संभावना होगी, मैंने 1 के बजाय 10 क्षेत्रों के साथ संरचना / कक्षाओं के लिए परीक्षण जोड़े हैं। आश्चर्यजनक रूप से, परिणाम बहुत भिन्न नहीं होते हैं।
मूल परिणाम (1 जून 2014):
(1 क्षेत्र के साथ संरचना / वर्ग पर दौड़े, 10 नहीं)
स्विफ्ट 1.2, Xcode 6.3.2 के रूप में, iPhone 5S, iOS 8.3 पर रिलीज़ बिल्ड चल रहा है, औसतन 5 से अधिक रन
class
संस्करण 9.788332333s लियाstruct
संस्करण ने 0.010532942s (900 गुना तेज) लियापुराने परिणाम (अज्ञात समय से)
(1 क्षेत्र के साथ संरचना / वर्ग पर दौड़े, 10 नहीं)
मेरी मैकबुक प्रो पर रिलीज़ बिल्ड के साथ:
class
संस्करण १.१००८२ सेकंड ले लियाstruct
संस्करण ०.०२३२४ सेकंड लिया (50 गुना तेजी से)मैंने इसके लिए सरल उदाहरण दिए हैं। https://github.com/objc-swift/swift-classes-vs-structures
संरचनाएं तेजी से विरासत में नहीं मिल सकती हैं। अगर तुम चाहते हो
class Vehicle{
}
class Car : Vehicle{
}
एक कक्षा के लिए जाओ।
स्विफ्ट संरचनाएं संदर्भ से गुजरती हैं और क्लास इंस्टेंस संदर्भ से गुजरती हैं।
संरचना स्थिर और चर
उदाहरण (WWDC 2014 में प्रयुक्त)
struct Point{
var x = 0.0;
var y = 0.0;
}
बिंदु नामक एक संरचना को परिभाषित करता है।
var point = Point(x:0.0,y:2.0)
अब अगर मैं एक्स को बदलने की कोशिश करता हूं। इसकी एक वैध अभिव्यक्ति है।
point.x = 5
लेकिन अगर मैंने एक बिंदु को स्थिर के रूप में परिभाषित किया है।
let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.
इस मामले में संपूर्ण बिंदु अपरिवर्तनीय स्थिर है।
अगर मैंने इसके बजाय एक क्लास प्वाइंट का उपयोग किया है तो यह एक वैध अभिव्यक्ति है। क्योंकि एक कक्षा में अपरिवर्तनीय स्थिरांक उस वर्ग के संदर्भ में होता है, जिसके उदाहरण चर नहीं होते (जब तक कि उन चर को स्थिरांक के रूप में परिभाषित नहीं किया जाता)
यहाँ कुछ अन्य कारणों पर विचार किया गया है:
स्ट्रक्चर्स को एक स्वचालित इनिशियलाइज़र मिलता है जिसे आपको कोड में बनाए रखने की आवश्यकता नहीं है।
struct MorphProperty {
var type : MorphPropertyValueType
var key : String
var value : AnyObject
enum MorphPropertyValueType {
case String, Int, Double
}
}
var m = MorphProperty(type: .Int, key: "what", value: "blah")
एक कक्षा में इसे पाने के लिए, आपको इनिशियलाइज़र जोड़ना होगा, और इंटेस्टाइज़र को बनाए रखना होगा ...
बुनियादी संग्रह प्रकार जैसे Array
संरचनाएं हैं। जितना अधिक आप उन्हें अपने कोड में उपयोग करते हैं, उतना ही आपको संदर्भ के विपरीत मूल्य से गुजरने की आदत होगी। उदाहरण के लिए:
func removeLast(var array:[String]) {
array.removeLast()
println(array) // [one, two]
}
var someArray = ["one", "two", "three"]
removeLast(someArray)
println(someArray) // [one, two, three]
जाहिरा तौर पर अपरिवर्तनीयता बनाम उत्परिवर्तन एक बहुत बड़ा विषय है, लेकिन बहुत सारे स्मार्ट लोग अपरिवर्तनीयता के बारे में सोचते हैं - इस मामले में संरचना - बेहतर है। अपरिवर्तनीय वस्तुएं
internal
दायरे में उपलब्ध हो ।
mutating
ताकि आप इस बारे में स्पष्ट हो जाएं कि कौन से फ़ंक्शन उनके राज्य को बदलते हैं। लेकिन मूल्य प्रकार के रूप में उनकी प्रकृति महत्वपूर्ण है। यदि आप एक संरचना की घोषणा करते हैं तो आप let
उस पर किसी भी म्यूटिंग फ़ंक्शन को कॉल नहीं कर सकते। मूल्य प्रकार के माध्यम से बेहतर प्रोग्रामिंग पर WWDC 15 वीडियो इस पर एक उत्कृष्ट संसाधन है।
यह मानते हुए कि हम जानते हैं कि संरचना एक मूल्य प्रकार है और कक्षा एक संदर्भ प्रकार है ।
यदि आप नहीं जानते हैं कि मूल्य प्रकार और संदर्भ प्रकार क्या हैं तो देखें कि संदर्भ बनाम पासिंग मान के बीच अंतर क्या है?
मीकेश की पोस्ट पर आधारित :
... आइए पहले कुछ अतिवादी, स्पष्ट उदाहरणों को देखें। इंटेगर स्पष्ट रूप से कॉपी करने योग्य हैं। उन्हें मूल्य प्रकार होना चाहिए। नेटवर्क सॉकेट को समझदारी से कॉपी नहीं किया जा सकता है। उन्हें संदर्भ प्रकार होना चाहिए। अंक, जैसे कि x, y जोड़े, प्रतिलिपि योग्य हैं। उन्हें मूल्य प्रकार होना चाहिए। एक नियंत्रक जो एक डिस्क का प्रतिनिधित्व करता है उसे समझदारी से कॉपी नहीं किया जा सकता है। यह एक संदर्भ प्रकार होना चाहिए।
कुछ प्रकारों की प्रतिलिपि बनाई जा सकती है लेकिन यह ऐसा कुछ नहीं हो सकता है जिसे आप हर समय करना चाहते हैं। इससे पता चलता है कि उन्हें संदर्भ प्रकार होना चाहिए। उदाहरण के लिए, स्क्रीन पर एक बटन को कॉपी किया जा सकता है। प्रतिलिपि मूल के समान नहीं होगी। कॉपी पर क्लिक करने से मूल सक्रिय नहीं होगा। प्रतिलिपि स्क्रीन पर एक ही स्थान पर कब्जा नहीं करेगी। यदि आप बटन को चारों ओर से गुजरते हैं या इसे एक नए चर में डालते हैं, तो आप शायद मूल बटन को संदर्भित करना चाहते हैं, और आप केवल एक प्रतिलिपि बनाना चाहते हैं जब यह स्पष्ट रूप से अनुरोध किया जाएगा। इसका मतलब है कि आपका बटन प्रकार एक संदर्भ प्रकार होना चाहिए।
दृश्य और विंडो नियंत्रक एक समान उदाहरण हैं। हो सकता है कि वे नकल करने योग्य हों, बोधगम्य हों, लेकिन यह लगभग वैसा नहीं है जैसा आप करना चाहते हैं। उन्हें संदर्भ प्रकार होना चाहिए।
मॉडल प्रकारों के बारे में क्या? आपके पास एक उपयोगकर्ता प्रकार हो सकता है जो आपके सिस्टम पर एक उपयोगकर्ता का प्रतिनिधित्व कर रहा है, या एक उपयोगकर्ता द्वारा की गई कार्रवाई का प्रतिनिधित्व करने वाला अपराध प्रकार। ये बहुत नकल करने योग्य हैं, इसलिए उन्हें संभवतः मूल्य प्रकार होना चाहिए। हालाँकि, आप संभवतः प्रोग्राम के अन्य हिस्सों में दृश्यमान होने के लिए अपने प्रोग्राम में एक स्थान पर किए गए उपयोगकर्ता के अपराध के अपडेट चाहते हैं। इससे पता चलता है कि आपके उपयोगकर्ताओं को किसी प्रकार के उपयोगकर्ता नियंत्रक द्वारा प्रबंधित किया जाना चाहिए जो एक संदर्भ प्रकार होगा । जैसे
struct User {} class UserController { var users: [User] func add(user: User) { ... } func remove(userNamed: String) { ... } func ... }
संग्रह एक दिलचस्प मामला है। इनमें एरेज़ और डिक्शनरी, साथ ही स्ट्रिंग्स जैसी चीजें शामिल हैं। क्या वे कॉपी करने योग्य हैं? जाहिर है। क्या आप आसानी से और अक्सर ऐसा कुछ करना चाहते हैं? यह कम स्पष्ट है।
अधिकांश भाषाएं इसे "नहीं" कहती हैं और अपने संग्रह को संदर्भ प्रकार बनाती हैं। यह Objective-C और Java और Python और JavaScript और लगभग हर दूसरी भाषा में मैं सोच सकता हूँ, में सच है। (एक प्रमुख अपवाद एसटीएल संग्रह प्रकारों के साथ सी ++ है, लेकिन सी ++ भाषा की दुनिया का कहर ढा रही है जो सब कुछ अजीब तरीके से करता है।)
स्विफ्ट ने कहा "हाँ", जिसका अर्थ है कि एरे और डिक्शनरी और स्ट्रिंग जैसे प्रकार कक्षाओं के बजाय संरचना हैं। वे असाइनमेंट पर कॉपी किए जाते हैं, और उन्हें मापदंडों के रूप में पास करने पर। यह एक पूरी तरह से समझदार विकल्प है जब तक कि कॉपी सस्ती है, जिसे स्विफ्ट पूरा करने के लिए बहुत कोशिश करता है। ...
मैं व्यक्तिगत रूप से अपनी कक्षाओं का नाम नहीं देता। मैं आमतौर पर UserController के बजाय मेरा उपयोगकर्ता नाम बताता हूं लेकिन विचार समान है
जब आप किसी फ़ंक्शन की प्रत्येक आवृत्ति को ओवरराइड करना चाहते हैं, तो इसके अलावा कक्षा का उपयोग न करें अर्थात उनमें कोई साझा कार्यक्षमता न हो ।
इसलिए एक वर्ग के कई उपवर्ग होने के बजाय। एक प्रोटोकॉल के अनुरूप कई संरचनाओं का उपयोग करें।
जब आप अपने पुराने और नए मॉडल का डेल्टा / अंतर करना चाहते हैं, तो संरचनाओं के लिए एक और उचित मामला है। संदर्भ प्रकारों के साथ आप बॉक्स से बाहर नहीं कर सकते। मान प्रकार के साथ म्यूटेशन साझा नहीं किए जाते हैं।
कुछ फायदे:
संरचना वर्ग की तुलना में अधिक तेज है। इसके अलावा, यदि आपको विरासत की आवश्यकता है तो आपको क्लास का उपयोग करना चाहिए। सबसे महत्वपूर्ण बिंदु यह है कि कक्षा संदर्भ प्रकार है जबकि संरचना मूल्य प्रकार है। उदाहरण के लिए,
class Flight {
var id:Int?
var description:String?
var destination:String?
var airlines:String?
init(){
id = 100
description = "first ever flight of Virgin Airlines"
destination = "london"
airlines = "Virgin Airlines"
}
}
struct Flight2 {
var id:Int
var description:String
var destination:String
var airlines:String
}
अब दोनों का उदाहरण बनाते हैं।
var flightA = Flight()
var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )
अब इन उदाहरणों को आईडी, विवरण, गंतव्य आदि को संशोधित करने वाले दो कार्यों को पास करने देता है।
func modifyFlight(flight:Flight) -> Void {
flight.id = 200
flight.description = "second flight of Virgin Airlines"
flight.destination = "new york"
flight.airlines = "Virgin Airlines"
}
भी,
func modifyFlight2(flight2: Flight2) -> Void {
var passedFlight = flight2
passedFlight.id = 200
passedFlight.description = "second flight from virgin airlines"
}
इसलिए,
modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)
अब अगर हम फ्लाइट की आईडी और विवरण प्रिंट करते हैं, तो हम प्राप्त करते हैं
id = 200
description = "second flight of Virgin Airlines"
यहां, हम देख सकते हैं कि फ्लाइट का आईडी और विवरण बदल दिया गया है, क्योंकि संशोधित विधि में पारित पैरामीटर वास्तव में फ्लाइटा ऑब्जेक्ट (संदर्भ प्रकार) के मेमोरी पते को इंगित करता है।
अब अगर हम FLightB उदाहरण की आईडी और विवरण को प्रिंट करते हैं,
id = 100
description = "first ever flight of Virgin Airlines"
यहां हम देख सकते हैं कि फ़्लाइटबी इंस्टेंस को बदला नहीं गया है क्योंकि मॉडिफाइड 2 विधि में, फ़्लाइट 2 का वास्तविक उदाहरण संदर्भ (वैल्यू टाइप) के बजाय पास किया गया है।
Here we can see that the FlightB instance is not changed
Structs
हैं value type
और Classes
हैंreference type
एक value
प्रकार का उपयोग करें जब:
एक reference
प्रकार का उपयोग करें जब:
आगे की जानकारी Apple प्रलेखन में भी मिल सकती है
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
अतिरिक्त जानकारी
ढेर में स्विफ्ट मान प्रकार रखे जाते हैं। एक प्रक्रिया में, प्रत्येक थ्रेड का अपना स्टैक स्थान होता है, इसलिए कोई अन्य थ्रेड सीधे आपके मान प्रकार तक नहीं पहुंच पाएगा। इसलिए कोई दौड़ की स्थिति, ताले, गतिरोध या किसी भी संबंधित थ्रेड सिंक्रनाइज़ेशन जटिलता नहीं है।
मूल्य प्रकारों को गतिशील मेमोरी आवंटन या संदर्भ गणना की आवश्यकता नहीं होती है, जो दोनों ही महंगे ऑपरेशन हैं। एक ही समय में मूल्य प्रकार के तरीकों को सांख्यिकीय रूप से भेजा जाता है। ये प्रदर्शन के मामले में मूल्य प्रकारों के पक्ष में एक बड़ा लाभ पैदा करते हैं।
यहां एक अनुस्मारक के रूप में स्विफ्ट की एक सूची है
मूल्य प्रकार:
संदर्भ प्रकार:
मान प्रकार बनाम संदर्भ प्रकार के परिप्रेक्ष्य से प्रश्न का उत्तर देना, इस Apple ब्लॉग पोस्ट से यह बहुत सरल प्रतीत होगा:
मान प्रकार का उपयोग करें [जैसे संरचना, enum] जब:
- उदाहरण के साथ डेटा की तुलना == समझ में आता है
- आप चाहते हैं कि स्वतंत्र राज्य की प्रतियां हों
- डेटा को कई थ्रेड्स में कोड में उपयोग किया जाएगा
एक संदर्भ प्रकार का उपयोग करें [जैसे वर्ग] जब:
- उदाहरण के साथ तुलना पहचान === समझ में आता है
- आप साझा, परिवर्तनशील स्थिति बनाना चाहते हैं
जैसा कि उस लेख में उल्लेख किया गया है, बिना लेखन गुणों वाला एक वर्ग एक संरचना के साथ पहचान के साथ व्यवहार करेगा, (मैं जोड़ूंगा) एक चेतावनी: संरचनाएं थ्रेड-सुरक्षित मॉडल के लिए सबसे अच्छी हैं - आधुनिक ऐप आर्किटेक्चर में एक तेजी से आसन्न आवश्यकता।
जिन कक्षाओं में आपको विरासत मिलती है और जिन्हें संदर्भ द्वारा पारित किया जाता है, संरचना में वंशानुक्रम नहीं होता है और मूल्य द्वारा पारित किया जाता है।
स्विफ्ट पर महान डब्ल्यूडब्ल्यूडीसी सत्र हैं, इस विशिष्ट प्रश्न का उत्तर उनमें से एक में बारीकी से दिया गया है। सुनिश्चित करें कि आप उन्हें देखते हैं, क्योंकि यह आपको बहुत तेज़ी से गति करने के लिए मिलेगा, फिर भाषा गाइड या आईबुक।
मैं यह नहीं कहूंगा कि संरचनाएं कम कार्यक्षमता प्रदान करती हैं।
निश्चित रूप से, म्यूटिंग फ़ंक्शन को छोड़कर स्वयं अपरिवर्तनीय है, लेकिन यह इसके बारे में है।
वंशानुक्रम तब तक ठीक काम करता है जब तक आप अच्छे पुराने विचार से चिपके रहते हैं कि हर वर्ग अमूर्त या अंतिम होना चाहिए।
अमूर्त वर्गों को प्रोटोकॉल के रूप में और अंतिम वर्गों को संरचना के रूप में लागू करें।
स्ट्रक्चर्स के बारे में अच्छी बात यह है कि आप साझा किए गए उत्परिवर्तनीय राज्य बनाए बिना अपने खेतों को उत्परिवर्तित कर सकते हैं क्योंकि लिखने पर प्रतिलिपि इस बात का ध्यान रखती है कि :)
इसीलिए निम्नलिखित उदाहरण में गुण / क्षेत्र सभी परिवर्तनशील हैं, जो मैं जावा या सी # या स्विफ्ट कक्षाओं में नहीं करूंगा ।
उदाहरण में "उदाहरण" नाम के समारोह में नीचे की ओर गंदे और सीधे उपयोग के साथ विरासत की संरचना:
protocol EventVisitor
{
func visit(event: TimeEvent)
func visit(event: StatusEvent)
}
protocol Event
{
var ts: Int64 { get set }
func accept(visitor: EventVisitor)
}
struct TimeEvent : Event
{
var ts: Int64
var time: Int64
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
}
protocol StatusEventVisitor
{
func visit(event: StatusLostStatusEvent)
func visit(event: StatusChangedStatusEvent)
}
protocol StatusEvent : Event
{
var deviceId: Int64 { get set }
func accept(visitor: StatusEventVisitor)
}
struct StatusLostStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var reason: String
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
struct StatusChangedStatusEvent : StatusEvent
{
var ts: Int64
var deviceId: Int64
var newStatus: UInt32
var oldStatus: UInt32
func accept(visitor: EventVisitor)
{
visitor.visit(self)
}
func accept(visitor: StatusEventVisitor)
{
visitor.visit(self)
}
}
func readEvent(fd: Int) -> Event
{
return TimeEvent(ts: 123, time: 56789)
}
func example()
{
class Visitor : EventVisitor
{
var status: UInt32 = 3;
func visit(event: TimeEvent)
{
print("A time event: \(event)")
}
func visit(event: StatusEvent)
{
print("A status event: \(event)")
if let change = event as? StatusChangedStatusEvent
{
status = change.newStatus
}
}
}
let visitor = Visitor()
readEvent(1).accept(visitor)
print("status: \(visitor.status)")
}
स्विफ्ट में, एक नया प्रोग्रामिंग पैटर्न प्रोटोकॉल ओरिएंटेड प्रोग्रामिंग के रूप में जाना जाता है।
रचनात्मक पैटर्न:
स्विफ्ट में, स्ट्रक्चर एक वैल्यू टाइप है जो अपने आप क्लोन हो जाता है। इसलिए हमें मुक्त करने के लिए प्रोटोटाइप पैटर्न को लागू करने के लिए आवश्यक व्यवहार मिलता है।
जबकि कक्षाएं संदर्भ प्रकार हैं, जो असाइनमेंट के दौरान स्वचालित रूप से क्लोन नहीं की जाती हैं। प्रोटोटाइप पैटर्न को लागू करने के लिए, कक्षाओं को NSCopying
प्रोटोकॉल को अपनाना होगा ।
उथला प्रतिलिपि केवल संदर्भ को डुप्लिकेट करती है, जो उन वस्तुओं को इंगित करती है जबकि गहरी प्रतिलिपि ऑब्जेक्ट के संदर्भ को दोहराती है।
प्रत्येक संदर्भ प्रकार के लिए गहरी प्रतिलिपि लागू करना एक कठिन कार्य बन गया है। यदि वर्गों में आगे संदर्भ प्रकार शामिल हैं, तो हमें प्रत्येक संदर्भ गुणों के लिए प्रोटोटाइप पैटर्न लागू करना होगा। और फिर हमें वास्तव में प्रोटोकॉल को लागू करके पूरे ऑब्जेक्ट ग्राफ को कॉपी करना होगा ।NSCopying
class Contact{
var firstName:String
var lastName:String
var workAddress:Address // Reference type
}
class Address{
var street:String
...
}
स्ट्रक्चर्स और एनम का उपयोग करके , हमने अपना कोड सरल बना दिया क्योंकि हमें कॉपी लॉजिक को लागू नहीं करना है।
कई कोको एपीआई को NSObject उपवर्गों की आवश्यकता होती है, जो आपको कक्षा का उपयोग करने के लिए मजबूर करता है। लेकिन इसके अलावा, आप एप्पल के स्विफ्ट ब्लॉग से निम्नलिखित मामलों का उपयोग करके यह तय कर सकते हैं कि एक स्ट्रक्चर / एनम वैल्यू टाइप या क्लास रेफरेंस टाइप का उपयोग करना है या नहीं।
इन उत्तरों में एक बिंदु पर ध्यान नहीं दिया जा रहा है कि एक वर्ग बनाम एक संरचना को धारण करने वाला एक चर हो सकता है let
फिर भी वस्तु के गुणों पर परिवर्तन की अनुमति देता है, जबकि आप एक संरचना के साथ ऐसा नहीं कर सकते।
यह उपयोगी है यदि आप चाहते हैं कि चर कभी किसी अन्य वस्तु की ओर न आए, लेकिन फिर भी वस्तु को संशोधित करने की आवश्यकता होती है, अर्थात कई उदाहरण चर होने की स्थिति में, जिन्हें आप एक के बाद एक अपडेट करना चाहते हैं। यदि यह एक संरचना है, तो आपको ऐसा करने के लिए चर को पूरी तरह से दूसरी वस्तु पर रीसेट करने की अनुमति देनी चाहिए var
, क्योंकि स्विफ्ट में एक निरंतर मूल्य प्रकार शून्य उत्परिवर्तन को ठीक से अनुमति देता है, जबकि संदर्भ प्रकार (कक्षाएं) इस तरह का व्यवहार नहीं करते हैं।
जैसा कि संरचना मूल्य प्रकार हैं और आप मेमोरी को बहुत आसानी से बना सकते हैं जो स्टैक में संग्रहीत करता है। विनाश आसानी से सुलभ हो सकता है और कार्य के दायरे के बाद स्टैक के शीर्ष से पॉप के माध्यम से स्टैक मेमोरी से आसानी से डील किया जाता है। दूसरी ओर वर्ग एक संदर्भ प्रकार है जो ढेर में संग्रहीत होता है और एक वर्ग वस्तु में किए गए परिवर्तन अन्य वस्तु पर प्रभाव डालते हैं क्योंकि वे कसकर युग्मित होते हैं और संदर्भ प्रकार। किसी संरचना के सभी सदस्य सार्वजनिक होते हैं जबकि एक वर्ग के सभी सदस्य निजी होते हैं ।
संरचना का नुकसान यह है कि यह विरासत में नहीं मिली है।
संरचना और वर्ग उपयोगकर्ता परिभाषित डेटा प्रकार हैं
डिफ़ॉल्ट रूप से, संरचना एक सार्वजनिक है जबकि वर्ग निजी है
क्लास इनकैप्सुलेशन के प्रिंसिपल को लागू करता है
एक वर्ग की वस्तुओं को ढेर स्मृति पर बनाया जाता है
कक्षा का उपयोग पुन: प्रयोज्य के लिए किया जाता है जबकि संरचना का उपयोग उसी संरचना में डेटा को समूहीकृत करने के लिए किया जाता है
संरचना डेटा सदस्यों को सीधे आरंभीकृत नहीं किया जा सकता है, लेकिन उन्हें संरचना के बाहर से सौंपा जा सकता है
क्लास डेटा सदस्यों को पैरामीटर कम कंस्ट्रक्टर द्वारा सीधे इनिशियलाइज़ किया जा सकता है और पैरामीटरेड कंस्ट्रक्टर द्वारा सौंपा जा सकता है