स्विफ्ट में एक वैकल्पिक एक प्रकार है जो या तो मूल्य या कोई मूल्य नहीं पकड़ सकता है। वैकल्पिक ?
को किसी भी प्रकार से जोड़कर लिखा जाता है :
var name: String? = "Bertie"
वैकल्पिक (जेनरिक के साथ) समझने के लिए सबसे कठिन स्विफ्ट अवधारणाओं में से एक है। क्योंकि वे कैसे लिखे और उपयोग किए जाते हैं, इस बात का गलत अंदाजा लगाना आसान है कि वे क्या हैं। सामान्य स्ट्रिंग बनाने के लिए ऊपर दिए गए वैकल्पिक की तुलना करें:
var name: String = "Bertie" // No "?" after String
वाक्य रचना से ऐसा लगता है कि वैकल्पिक स्ट्रिंग एक साधारण स्ट्रिंग के समान है। यह। एक वैकल्पिक स्ट्रिंग कुछ "वैकल्पिक" सेटिंग के साथ स्ट्रिंग नहीं है। यह स्ट्रिंग की एक विशेष किस्म नहीं है। एक स्ट्रिंग और एक वैकल्पिक स्ट्रिंग पूरी तरह से अलग प्रकार के होते हैं।
यहां यह जानना सबसे महत्वपूर्ण है: एक वैकल्पिक एक प्रकार का कंटेनर है। एक वैकल्पिक स्ट्रिंग एक कंटेनर है जिसमें एक स्ट्रिंग हो सकता है। एक वैकल्पिक Int एक कंटेनर है जिसमें एक Int हो सकता है। एक प्रकार के पार्सल के रूप में एक वैकल्पिक के बारे में सोचो। इससे पहले कि आप इसे खोलें (या वैकल्पिक की भाषा में "अनचाहे") आपको पता नहीं चलेगा कि इसमें कुछ है या कुछ नहीं है।
आप देख सकते हैं कि स्विफ्ट स्टैंडर्ड लाइब्रेरी में "वैकल्पिक" को किसी भी स्विफ्ट फ़ाइल में टाइप करके और उस पर it-क्लिक करके वैकल्पिक कैसे लागू किया जाता है। यहाँ परिभाषा का महत्वपूर्ण हिस्सा है:
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
वैकल्पिक सिर्फ एक है enum
जो दो मामलों में से एक हो सकता है: .none
या .some
। यदि यह है .some
, तो एक संबद्ध मूल्य है, जो ऊपर दिए गए उदाहरण में, String
"हैलो" होगा। एक वैकल्पिक संबंधित मूल्य को एक प्रकार देने के लिए जेनरिक का उपयोग करता है। वैकल्पिक स्ट्रिंग का प्रकार String
यह नहीं है Optional
, या अधिक सटीक है Optional<String>
।
सब कुछ स्विफ्ट वैकल्पिक के साथ करता है पढ़ने और लिखने के कोड को अधिक धाराप्रवाह बनाने के लिए जादू है। दुर्भाग्य से यह वास्तव में काम करने के तरीके को अस्पष्ट करता है। मैं बाद में कुछ ट्रिक्स से गुजरूंगा।
नोट: मैं वैकल्पिक चर के बारे में बात कर रहा हूँ, लेकिन वैकल्पिक स्थिरांक बनाना भी ठीक है। मैं सभी प्रकारों को उनके प्रकार के साथ चिह्नित करता हूं ताकि प्रकार के प्रकारों को समझने में आसानी हो, लेकिन आपको अपने कोड में नहीं होना चाहिए।
कैसे वैकल्पिक बनाने के लिए
एक वैकल्पिक बनाने के लिए, ?
उस प्रकार के बाद जोड़ें जिसे आप लपेटना चाहते हैं। कोई भी प्रकार वैकल्पिक हो सकता है, यहां तक कि आपके स्वयं के कस्टम प्रकार भी। आपके पास प्रकार और के बीच का स्थान नहीं हो सकता ?
।
var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)
// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}
वैकल्पिक का उपयोग करना
आप nil
यह देखने के लिए वैकल्पिक की तुलना कर सकते हैं कि क्या इसका मूल्य है:
var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
print("There is a name")
}
if name == nil { // Could also use an "else"
print("Name has no value")
}
यह थोड़ा भ्रमित करने वाला है। इसका तात्पर्य है कि एक वैकल्पिक या तो एक चीज है या कोई अन्य। यह या तो शून्य है या यह "बॉब" है। यह सच नहीं है, वैकल्पिक कुछ और में परिवर्तित नहीं होता है। इसे शून्य से तुलना करना आसान कोड को पढ़ने के लिए एक चाल है। यदि कोई वैकल्पिक शून्य के बराबर होता है, तो इसका अर्थ है कि वर्तमान में एनम सेट है .none
।
केवल वैकल्पिक शून्य हो सकते हैं
यदि आप गैर-वैकल्पिक चर को शून्य पर सेट करने का प्रयास करते हैं, तो आपको एक त्रुटि मिलेगी।
var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
वैकल्पिक देखने का एक अन्य तरीका सामान्य स्विफ्ट चर के पूरक के रूप में है। वे एक वैरिएबल के प्रतिरूप हैं जो एक मूल्य के लिए गारंटी है। स्विफ्ट एक सावधान भाषा है जो अस्पष्टता से नफरत करती है। अधिकांश चर को गैर-वैकल्पिक के रूप में परिभाषित किया जाता है, लेकिन कभी-कभी यह संभव नहीं होता है। उदाहरण के लिए, एक दृश्य नियंत्रक की कल्पना करें जो एक छवि को कैश या नेटवर्क से लोड करता है। यह समय उस छवि का हो सकता है या नहीं हो सकता है जब दृश्य नियंत्रक बनाया जाता है। छवि चर के लिए मान की गारंटी देने का कोई तरीका नहीं है। इस मामले में आपको इसे वैकल्पिक बनाना होगा। यह तब शुरू होता है nil
जब छवि को पुनः प्राप्त किया जाता है, वैकल्पिक को एक मूल्य मिलता है।
वैकल्पिक का उपयोग करने से प्रोग्रामर के इरादे का पता चलता है। ऑब्जेक्टिव-सी की तुलना में, जहां कोई भी वस्तु शून्य हो सकती है, स्विफ्ट के लिए आपको यह स्पष्ट होने की आवश्यकता है कि कब मूल्य गायब हो सकता है और कब अस्तित्व की गारंटी होगी।
एक वैकल्पिक का उपयोग करने के लिए, आप इसे "अनफ्रैप" करते हैं
एक String
वास्तविक के स्थान पर एक वैकल्पिक का उपयोग नहीं किया जा सकता है String
। एक वैकल्पिक के अंदर लिपटे मूल्य का उपयोग करने के लिए, आपको इसे खोलना होगा। वैकल्पिक को अनफ्रैप करने का सबसे सरल तरीका !
वैकल्पिक नाम के बाद जोड़ना है । इसे "बल अलिखित" कहा जाता है। यह वैकल्पिक (मूल प्रकार) के अंदर मान लौटाता है लेकिन यदि वैकल्पिक है nil
, तो यह रनटाइम क्रैश का कारण बनता है। अलिखित करने से पहले आपको सुनिश्चित होना चाहिए कि एक मूल्य है।
var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")
name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.
वैकल्पिक की जाँच करना और उसका उपयोग करना
चूँकि आपको हमेशा अल्टरनेपिंग और एक वैकल्पिक उपयोग करने से पहले नील की जांच करनी चाहिए, यह एक सामान्य पैटर्न है:
var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
let unwrappedMealPreference: String = mealPreference!
print("Meal: \(unwrappedMealPreference)") // or do something useful
}
इस पैटर्न में आप जांचते हैं कि एक मूल्य मौजूद है, फिर जब आप सुनिश्चित होते हैं कि आप इसे उपयोग करने के लिए एक अस्थायी स्थिर में मजबूर करते हैं। क्योंकि यह ऐसा करने के लिए एक सामान्य बात है, स्विफ्ट "अगर चलो" का उपयोग करके एक शॉर्टकट प्रदान करता है। इसे "वैकल्पिक बाध्यकारी" कहा जाता है।
var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
print("Meal: \(unwrappedMealPreference)")
}
यह एक अस्थायी स्थिरांक (या यदि आप के let
साथ परिवर्तनशील var
) बनाता है जिसका दायरा केवल if के ब्रेसिज़ के भीतर है। चूँकि "undrappedMealPreference" या "realMealPreference" जैसे नाम का उपयोग करना एक बोझ है, इसलिए स्विफ्ट आपको मूल चर नाम का पुन: उपयोग करने की अनुमति देता है, जिससे ब्रैकेट स्कोप के भीतर एक अस्थायी बना होता है
var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // separate from the other mealPreference
}
यह प्रदर्शित करने के लिए कुछ कोड है कि एक अलग चर का उपयोग किया जाता है:
var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"
वैकल्पिक बाध्यकारी शून्य के बराबर है या नहीं यह देखने के लिए जाँच करके वैकल्पिक बाइंडिंग कार्य करता है। यदि ऐसा नहीं होता है, तो यह प्रदान की गई स्थिरांक में वैकल्पिक को खोल देता है और ब्लॉक को निष्पादित करता है। Xcode 8.3 और बाद में (स्विफ्ट 3.1), इस तरह से एक वैकल्पिक प्रिंट करने की कोशिश करना एक बेकार चेतावनी का कारण होगा। debugDescription
इसे शांत करने के लिए वैकल्पिक का उपयोग करें :
print("\(mealPreference.debugDescription)")
इसके लिए वैकल्पिक क्या हैं?
वैकल्पिक उपयोग के दो मामले हैं:
- चीजें जो विफल हो सकती हैं (मुझे कुछ उम्मीद थी लेकिन मुझे कुछ नहीं मिला)
- चीजें जो अब कुछ भी नहीं हैं लेकिन बाद में कुछ हो सकती हैं (और इसके विपरीत)
कुछ ठोस उदाहरण:
- एक संपत्ति जो वहाँ है या नहीं हो सकता है, की तरह
middleName
या spouse
एक में Person
कक्षा
- एक विधि जो एक मान या कुछ भी नहीं लौटा सकती है, जैसे कि एक सरणी में मैच की खोज करना
- एक विधि जो या तो एक परिणाम दे सकती है या एक त्रुटि प्राप्त कर सकती है और कुछ भी नहीं लौटा सकती है, जैसे कि फ़ाइल की सामग्री को पढ़ने की कोशिश करना (जो आमतौर पर फ़ाइल के डेटा को लौटाता है) लेकिन फ़ाइल मौजूद नहीं है
- प्रतिनिधि गुण, जिन्हें हमेशा सेट नहीं करना पड़ता है और आमतौर पर आरंभ के बाद सेट किया जाता है
- के लिए
weak
कक्षाओं में गुण। जिस चीज को वे इंगित करते हैं, वह nil
किसी भी समय सेट किया जा सकता है
- एक बड़ा संसाधन जिसे स्मृति को पुनः प्राप्त करने के लिए जारी करना पड़ सकता है
- जब आपको यह जानने के लिए एक तरीका की आवश्यकता होती है कि कोई मान सेट किया गया है (डेटा अभी तक लोड नहीं किया गया है> डेटा) के बजाय एक अलग डेटाकोल्ड का उपयोग कर
Boolean
उद्देश्य-सी में विकल्प मौजूद नहीं हैं, लेकिन एक समतुल्य अवधारणा है, वापस लौटना। विधियाँ जो किसी वस्तु को वापस कर सकती हैं, उसके बदले शून्य लौटा सकती हैं। इसका अर्थ "एक वैध वस्तु की अनुपस्थिति" लिया जाता है और अक्सर यह कहा जाता है कि कुछ गलत हो गया था। यह केवल वस्तुनिष्ठ-सी वस्तुओं के साथ काम करता है, न कि आदिम या बुनियादी सी-प्रकार (एनम, स्ट्रक्चर्स) के साथ। उद्देश्य-सी में अक्सर इन मूल्यों की अनुपस्थिति का प्रतिनिधित्व करने के लिए विशेष प्रकार होते थे ( NSNotFound
जो वास्तव में NSIntegerMax
, kCLLocationCoordinate2DInvalid
एक अवैध समन्वय का प्रतिनिधित्व करने के लिए, -1
या कुछ नकारात्मक मूल्य का भी उपयोग किया जाता है)। कोडर को इन विशेष मूल्यों के बारे में जानना है, इसलिए उन्हें प्रत्येक मामले के लिए दस्तावेज और सीखना चाहिए। यदि कोई विधि nil
पैरामीटर के रूप में नहीं ले सकती है , तो इसे प्रलेखित किया जाना है। उद्देश्य-सी में,nil
एक संकेतक था जैसा कि सभी वस्तुओं को संकेत के रूप में परिभाषित किया गया था, लेकिन nil
एक विशिष्ट (शून्य) पते पर इंगित किया गया था। स्विफ्ट में, nil
एक शाब्दिक अर्थ है जो एक निश्चित प्रकार की अनुपस्थिति है।
की तुलना में nil
आप के रूप में किसी भी वैकल्पिक का उपयोग करने में सक्षम हो Boolean
:
let leatherTrim: CarExtras? = nil
if leatherTrim {
price = price + 1000
}
स्विफ्ट के अधिक हाल के संस्करणों में आपको उपयोग करना होगा leatherTrim != nil
। ऐसा क्यों है? समस्या यह है कि एक Boolean
वैकल्पिक में लपेटा जा सकता है। अगर आपको यह Boolean
पसंद है:
var ambiguous: Boolean? = false
इसके दो प्रकार के "झूठे" हैं, एक जहां कोई मूल्य नहीं है और एक जहां इसका मूल्य है, लेकिन मूल्य है false
। स्विफ्ट को अस्पष्टता से नफरत है इसलिए अब आपको हमेशा एक वैकल्पिक जांच करनी चाहिए nil
।
आप सोच सकते हैं कि एक वैकल्पिक बिंदु क्या Boolean
है? अन्य वैकल्पिकों की तरह .none
राज्य यह संकेत दे सकता है कि मूल्य अभी तक अज्ञात है। एक नेटवर्क कॉल के दूसरे छोर पर कुछ हो सकता है जो मतदान में कुछ समय लेता है। वैकल्पिक बूलियन को " थ्री-वैल्यू बूलियन " भी कहा जाता है
स्विफ्ट ट्रिक्स
वैकल्पिक काम करने के लिए स्विफ्ट कुछ तरकीबों का उपयोग करती है। साधारण दिखने वाले वैकल्पिक कोड की इन तीन पंक्तियों पर विचार करें;
var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }
इन पंक्तियों में से कोई भी संकलन नहीं करना चाहिए।
- पहली पंक्ति एक स्ट्रिंग स्ट्रिंग शाब्दिक, दो अलग-अलग प्रकारों का उपयोग करके एक वैकल्पिक स्ट्रिंग सेट करती है। भले ही यह एक
String
प्रकार के थे अलग हैं
- दूसरी पंक्ति दो अलग-अलग प्रकारों को शून्य करने के लिए एक वैकल्पिक स्ट्रिंग सेट करती है
- तीसरी पंक्ति एक वैकल्पिक स्ट्रिंग को शून्य, दो अलग-अलग प्रकारों से तुलना करती है
मैं वैकल्पिक के कुछ कार्यान्वयन विवरणों के माध्यम से जाऊंगा जो इन पंक्तियों को काम करने की अनुमति देते हैं।
एक वैकल्पिक बनाना
?
एक वैकल्पिक बनाने के लिए उपयोग कर रहा है वाक्य रचना चीनी, स्विफ्ट कंपाइलर द्वारा सक्षम है। यदि आप इसे लंबा करना चाहते हैं, तो आप इस तरह से एक वैकल्पिक बना सकते हैं:
var name: Optional<String> = Optional("Bob")
यह Optional
पहला इनिशियलाइज़र कहलाता है public init(_ some: Wrapped)
, जो कोष्ठक के भीतर उपयोग किए गए प्रकार से वैकल्पिक से जुड़े प्रकार को संक्रमित करता है।
वैकल्पिक बनाने और स्थापित करने का समान लंबा तरीका:
var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")
के लिए एक वैकल्पिक सेटिंग nil
आप बिना प्रारंभिक मूल्य के एक वैकल्पिक बना सकते हैं, या nil
दोनों के प्रारंभिक मूल्य के साथ एक बना सकते हैं (दोनों का एक ही परिणाम है)।
var name: String?
var name: String? = nil
समान के लिए वैकल्पिक विकल्प को nil
प्रोटोकॉल ExpressibleByNilLiteral
(पहले नामित NilLiteralConvertible
) द्वारा सक्षम किया गया है । वैकल्पिक को Optional
दूसरे इनिशियलाइज़र के साथ बनाया गया है public init(nilLiteral: ())
। डॉक्स का कहना है कि आपको ExpressibleByNilLiteral
वैकल्पिक के अलावा किसी भी चीज़ के लिए उपयोग नहीं करना चाहिए , क्योंकि इससे आपके कोड में नील का अर्थ बदल जाएगा, लेकिन ऐसा करना संभव है:
class Clint: ExpressibleByNilLiteral {
var name: String?
required init(nilLiteral: ()) {
name = "The Man with No Name"
}
}
let clint: Clint = nil // Would normally give an error
print("\(clint.name)")
एक ही प्रोटोकॉल आपको पहले से निर्मित वैकल्पिक को सेट करने की अनुमति देता है nil
। हालांकि इसकी अनुशंसा नहीं की जाती है, आप सीधे nil शाब्दिक इनिलाइज़र का उपयोग कर सकते हैं:
var name: Optional<String> = Optional(nilLiteral: ())
के लिए एक वैकल्पिक तुलना nil
वैकल्पिक दो विशेष "==" और "! =" ऑपरेटर को परिभाषित करते हैं, जिसे आप Optional
परिभाषा में देख सकते हैं । पहला ==
आपको यह जांचने की अनुमति देता है कि क्या कोई वैकल्पिक शून्य के बराबर है। दो अलग-अलग वैकल्पिक जो कि .none पर सेट किए गए हैं, यदि संबंधित प्रकार समान हैं, तो हमेशा समान होंगे। जब आप शून्य से तुलना करते हैं, तो पर्दे के पीछे स्विफ्ट एक ही संबद्ध प्रकार का एक वैकल्पिक बनाता है, जो सेट किया जाता है। फिर उस तुलना के लिए उपयोग करता है।
// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
print("tuxedoRequired is nil")
}
दूसरा ==
ऑपरेटर आपको दो वैकल्पिकों की तुलना करने की अनुमति देता है। दोनों को एक ही प्रकार का होना चाहिए और उस प्रकार के अनुरूप होना चाहिए Equatable
(प्रोटोकॉल जो नियमित "==" ऑपरेटर) के साथ चीजों की तुलना करने की अनुमति देता है। स्विफ्ट (संभवतः) दो मूल्यों को उजागर करता है और सीधे उनकी तुलना करता है। यह उस मामले को भी संभालता है जहां एक या दोनों वैकल्पिक हैं .none
। nil
शाब्दिक की तुलना के बीच अंतर पर ध्यान दें ।
इसके अलावा, यह आपको किसी भी Equatable
प्रकार के वैकल्पिक रैपिंग की तुलना करने की अनुमति देता है :
let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
print("It's a match!") // Prints "It's a match!"
}
पर्दे के पीछे, स्विफ्ट तुलना के पहले गैर-वैकल्पिक को वैकल्पिक के रूप में लपेटता है। यह शाब्दिक के साथ भी काम करता है ( if 23 == numberFromString {
)
मैंने कहा कि दो ==
ऑपरेटर हैं, लेकिन वास्तव में एक तीसरा है जो आपको nil
तुलना के बाईं ओर रखने की अनुमति देता है
if nil == name { ... }
नामकरण वैकल्पिक
गैर-वैकल्पिक प्रकारों से अलग प्रकार के वैकल्पिक नामकरण के लिए कोई स्विफ्ट सम्मेलन नहीं है। लोग यह दिखाने के लिए कुछ नाम जोड़ने से बचते हैं कि यह एक वैकल्पिक है (जैसे "alternMiddleName", या "possibleNumberAsString") और घोषणा को दिखाने दें कि यह एक वैकल्पिक प्रकार है। यह मुश्किल हो जाता है जब आप किसी वैकल्पिक से मूल्य को रखने के लिए कुछ नाम देना चाहते हैं। "मध्यनाम" नाम का अर्थ है कि यह एक स्ट्रिंग प्रकार है, इसलिए जब आप इसमें से स्ट्रिंग मान निकालते हैं, तो आप अक्सर "realMiddleName" या "unwrappedMiddleName" या "realMieldName" जैसे नामों के साथ समाप्त कर सकते हैं। वैकल्पिक बाइंडिंग का उपयोग करें और इसके चारों ओर प्राप्त करने के लिए चर नाम का पुन: उपयोग करें।
आधिकारिक परिभाषा
से "मूल बातें" में स्विफ्ट प्रोग्रामिंग भाषा :
स्विफ्ट भी वैकल्पिक प्रकारों का परिचय देता है, जो एक मूल्य की अनुपस्थिति को संभालते हैं। वैकल्पिक का कहना है कि या तो "एक मूल्य है, और यह x के बराबर है" या "वहाँ एक मूल्य नहीं है"। उद्देश्य-सी में पॉइंटर्स के साथ नील का उपयोग करने के लिए वैकल्पिक हैं, लेकिन वे किसी भी प्रकार के लिए काम करते हैं, न कि केवल कक्षाएं। वैकल्पिक उद्देश्य-सी में नील बिंदुओं की तुलना में अधिक सुरक्षित और अधिक अभिव्यंजक हैं और स्विफ्ट की कई सबसे शक्तिशाली विशेषताओं के केंद्र में हैं।
वैकल्पिक इस तथ्य का एक उदाहरण है कि स्विफ्ट एक प्रकार की सुरक्षित भाषा है। स्विफ्ट आपके कोड के साथ काम करने वाले मूल्यों के प्रकारों के बारे में स्पष्ट होने में मदद करता है। यदि आपके कोड का हिस्सा स्ट्रिंग की अपेक्षा करता है, तो टाइप सुरक्षा आपको इसे गलती से इंट पास करने से रोकती है। यह आपको विकास प्रक्रिया में जितनी जल्दी हो सके त्रुटियों को पकड़ने और ठीक करने में सक्षम बनाता है।
खत्म करने के लिए, यहाँ वैकल्पिक के बारे में 1899 से एक कविता है:
कल सीढ़ी पर
मैं एक आदमी से मिला जो वहां नहीं था
वह आज फिर नहीं था
मैं चाहता हूं, काश वह एंटीगोनिश चला जाता
और अधिक संसाधनों: