Swift Language
जेनेरिक्स
खोज…
टिप्पणियों
जेनेरिक कोड आपको लचीले, पुन: प्रयोज्य कार्यों और प्रकारों को लिखने में सक्षम बनाता है जो आपके द्वारा परिभाषित आवश्यकताओं के अधीन किसी भी प्रकार के साथ काम कर सकते हैं। आप ऐसा कोड लिख सकते हैं जो दोहराव से बचता है और अपने इरादे को स्पष्ट, अमूर्त तरीके से व्यक्त करता है।
जेनेटिक्स स्विफ्ट की सबसे शक्तिशाली विशेषताओं में से एक है, और स्विफ्ट मानक पुस्तकालय का अधिकांश हिस्सा जेनेरिक कोड के साथ बनाया गया है। उदाहरण के लिए, स्विफ्ट के
Array
औरDictionary
प्रकार दोनों सामान्य संग्रह हैं। आप एक सरणी बना सकते हैं जोInt
मान रखती है, या एक सरणी जोString
मान रखती है, या वास्तव में किसी अन्य प्रकार के लिए एक सरणी है जो स्विफ्ट में बनाई जा सकती है। इसी तरह, आप किसी भी निर्दिष्ट प्रकार के मूल्यों को संग्रहीत करने के लिए एक शब्दकोश बना सकते हैं, और उस प्रकार की कोई सीमाएं नहीं हैं।
जेनेरिक प्लेसहोल्डर प्रकारों को बाध्य करना
प्रोटोकॉल को लागू करने के लिए एक सामान्य वर्ग के प्रकार के मापदंडों को लागू करना संभव है , उदाहरण के लिए, Equatable
class MyGenericClass<Type: Equatable>{
var value: Type
init(value: Type){
self.value = value
}
func getValue() -> Type{
return self.value
}
func valueEquals(anotherValue: Type) -> Bool{
return self.value == anotherValue
}
}
जब भी हम एक नया MyGenericClass
, तो टाइप पैरामीटर को Equatable
प्रोटोकॉल लागू करना Equatable
है (यह सुनिश्चित करना कि टाइप पैरामीटर ==
का उपयोग करके उसी प्रकार के दूसरे वेरिएबल से तुलना की जा सकती है)
let myFloatGeneric = MyGenericClass<Double>(value: 2.71828) // valid
let myStringGeneric = MyGenericClass<String>(value: "My String") // valid
// "Type [Int] does not conform to protocol 'Equatable'"
let myInvalidGeneric = MyGenericClass<[Int]>(value: [2])
let myIntGeneric = MyGenericClass<Int>(value: 72)
print(myIntGeneric.valueEquals(72)) // true
print(myIntGeneric.valueEquals(-274)) // false
// "Cannot convert value of type 'String' to expected argument type 'Int'"
print(myIntGeneric.valueEquals("My String"))
मूल बातें
जेनरिक प्रकार के प्लेसहोल्डर हैं, जिससे आप लचीले कोड लिख सकते हैं जिसे कई प्रकारों में लागू किया जा सकता है। Any
पर Any
जेनेरिक का उपयोग करने का लाभ यह है कि वे अभी भी संकलक को मजबूत प्रकार-सुरक्षा लागू करने की अनुमति देते हैं।
एक सामान्य प्लेसहोल्डर कोण कोष्ठक <>
परिभाषित किया गया है।
सामान्य कार्य
फ़ंक्शन के लिए , इस प्लेसहोल्डर को फ़ंक्शन नाम के बाद रखा गया है:
/// Picks one of the inputs at random, and returns it
func pickRandom<T>(_ a:T, _ b:T) -> T {
return arc4random_uniform(2) == 0 ? a : b
}
इस मामले में, सामान्य प्लेसहोल्डर T
। जब आप फ़ंक्शन को कॉल करने के लिए आते हैं, तो स्विफ्ट आपके लिए T
के प्रकार का अनुमान लगा सकता है (क्योंकि यह बस एक वास्तविक प्रकार के लिए प्लेसहोल्डर के रूप में कार्य करता है)।
let randomOutput = pickRandom(5, 7) // returns an Int (that's either 5 or 7)
यहाँ हम फंक्शन में दो पूर्णांक पास कर रहे हैं। इसलिए स्विफ्ट T == Int
संदर्भ दे रहा है - इस प्रकार फ़ंक्शन हस्ताक्षर (Int, Int) -> Int
से अनुमानित है।
जेनेरिक की पेशकश की मजबूत प्रकार की सुरक्षा के कारण - फ़ंक्शन के तर्क और वापसी दोनों एक ही प्रकार के होने चाहिए। इसलिए निम्नलिखित संकलन नहीं होगा:
struct Foo {}
let foo = Foo()
let randomOutput = pickRandom(foo, 5) // error: cannot convert value of type 'Int' to expected argument type 'Foo'
सामान्य प्रकार
कक्षाओं , संरचनाओं या एनम के साथ जेनरिक का उपयोग करने के लिए, आप टाइप नाम के बाद जेनेरिक प्लेसहोल्डर को परिभाषित कर सकते हैं।
class Bar<T> {
var baz : T
init(baz:T) {
self.baz = baz
}
}
जब आप Bar
का उपयोग करने के लिए आते हैं, तो इस सामान्य प्लेसहोल्डर को एक प्रकार की आवश्यकता होगी। इस मामले में, यह init(baz:T)
से पता लगाया जा सकता है।
let bar = Bar(baz: "a string") // bar's type is Bar<String>
यहाँ जेनेरिक प्लेसहोल्डर T
टाइप String
होने का अनुमान है, इस प्रकार एक Bar<String>
उदाहरण बना रहा है। आप स्पष्ट रूप से प्रकार भी निर्दिष्ट कर सकते हैं:
let bar = Bar<String>(baz: "a string")
जब एक प्रकार के साथ उपयोग किया जाता है, तो दिए गए जेनेरिक प्लेसहोल्डर दिए गए उदाहरण के पूरे जीवनकाल के लिए अपने प्रकार को रखेंगे, और आरंभ के बाद नहीं बदला जा सकता है। इसलिए जब आप प्रॉपर्टी baz
एक्सेस करते हैं, तो यह हमेशा इस दिए गए उदाहरण के लिए String
का प्रकार होगा।
let str = bar.baz // of type String
सामान्य प्रकार के आसपास पासिंग
जब आप जेनेरिक प्रकारों के आस-पास से गुजरते हैं, तो ज्यादातर मामलों में आपको जेनेरिक प्लेसहोल्डर प्रकार के बारे में स्पष्ट होना चाहिए जो आप अपेक्षा करते हैं। उदाहरण के लिए, फ़ंक्शन इनपुट के रूप में:
func takeABarInt(bar:Bar<Int>) {
...
}
यह फ़ंक्शन केवल एक Bar<Int>
स्वीकार करेगा। एक Bar
उदाहरण में पारित करने का प्रयास जहां सामान्य प्लेसहोल्डर प्रकार Int
नहीं है, एक संकलक त्रुटि के परिणामस्वरूप होगा।
जेनेरिक प्लेसहोल्डर नामकरण
जेनेरिक प्लेसहोल्डर नाम केवल एकल अक्षरों तक सीमित नहीं हैं। यदि दिया गया प्लेसहोल्डर एक सार्थक अवधारणा का प्रतिनिधित्व करता है, तो आपको इसे एक वर्णनात्मक नाम देना चाहिए। उदाहरण के लिए, स्विफ्ट के Array
में Element
नामक एक जेनेरिक प्लेसहोल्डर होता है, जो दिए गए Array
उदाहरण के तत्व प्रकार को परिभाषित करता है।
public struct Array<Element> : RandomAccessCollection, MutableCollection {
...
}
सामान्य वर्ग के उदाहरण
प्रकार पैरामीटर के साथ एक सामान्य वर्ग Type
class MyGenericClass<Type>{
var value: Type
init(value: Type){
self.value = value
}
func getValue() -> Type{
return self.value
}
func setValue(value: Type){
self.value = value
}
}
अब हम एक प्रकार के पैरामीटर का उपयोग करके नई ऑब्जेक्ट बना सकते हैं
let myStringGeneric = MyGenericClass<String>(value: "My String Value")
let myIntGeneric = MyGenericClass<Int>(value: 42)
print(myStringGeneric.getValue()) // "My String Value"
print(myIntGeneric.getValue()) // 42
myStringGeneric.setValue("Another String")
myIntGeneric.setValue(1024)
print(myStringGeneric.getValue()) // "Another String"
print(myIntGeneric.getValue()) // 1024
कई प्रकार के मापदंडों के साथ जेनरिक भी बनाए जा सकते हैं
class AnotherGenericClass<TypeOne, TypeTwo, TypeThree>{
var value1: TypeOne
var value2: TypeTwo
var value3: TypeThree
init(value1: TypeOne, value2: TypeTwo, value3: TypeThree){
self.value1 = value1
self.value2 = value2
self.value3 = value3
}
func getValueOne() -> TypeOne{return self.value1}
func getValueTwo() -> TypeTwo{return self.value2}
func getValueThree() -> TypeThree{return self.value3}
}
और उसी तरह से उपयोग किया जाता है
let myGeneric = AnotherGenericClass<String, Int, Double>(value1: "Value of pi", value2: 3, value3: 3.14159)
print(myGeneric.getValueOne() is String) // true
print(myGeneric.getValueTwo() is Int) // true
print(myGeneric.getValueThree() is Double) // true
print(myGeneric.getValueTwo() is String) // false
print(myGeneric.getValueOne()) // "Value of pi"
print(myGeneric.getValueTwo()) // 3
print(myGeneric.getValueThree()) // 3.14159
जेनेरिक क्लास इनहेरिटेंस
जेनेरिक कक्षाएं विरासत में मिल सकती हैं:
// Models
class MyFirstModel {
}
class MySecondModel: MyFirstModel {
}
// Generic classes
class MyFirstGenericClass<T: MyFirstModel> {
func doSomethingWithModel(model: T) {
// Do something here
}
}
class MySecondGenericClass<T: MySecondModel>: MyFirstGenericClass<T> {
override func doSomethingWithModel(model: T) {
super.doSomethingWithModel(model)
// Do more things here
}
}
सरणी क्रियाओं को सरल बनाने के लिए सामान्य ज्ञान का उपयोग करना
एक फंक्शन जो ऑब्जेक्ट ओरिएंटेड रिमूवल फंक्शन बनाकर एरे की कार्यक्षमता बढ़ाता है।
// Need to restrict the extension to elements that can be compared.
// The `Element` is the generics name defined by Array for its item types.
// This restriction also gives us access to `index(of:_)` which is also
// defined in an Array extension with `where Element: Equatable`.
public extension Array where Element: Equatable {
/// Removes the given object from the array.
mutating func remove(_ element: Element) {
if let index = self.index(of: element ) {
self.remove(at: index)
} else {
fatalError("Removal error, no such element:\"\(element)\" in array.\n")
}
}
}
प्रयोग
var myArray = [1,2,3]
print(myArray)
// Prints [1,2,3]
किसी इंडेक्स की आवश्यकता के बिना किसी तत्व को निकालने के लिए फ़ंक्शन का उपयोग करें। बस वस्तु को हटाने के लिए पास करें।
myArray.remove(2)
print(myArray)
// Prints [1,3]
टाइप-सेफ्टी बढ़ाने के लिए जेनेरिक का उपयोग करें
आइए जेनरिक का उपयोग किए बिना इस उदाहरण को लेते हैं
protocol JSONDecodable {
static func from(_ json: [String: Any]) -> Any?
}
जब तक आप वास्तव में इसका उपयोग नहीं करते तब तक प्रोटोकॉल घोषणा ठीक लगती है।
let myTestObject = TestObject.from(myJson) as? TestObject
आपको TestObject
परिणाम क्यों डालना है? प्रोटोकॉल घोषणा में Any
वापसी प्रकार के कारण।
जेनरिक का उपयोग करके आप इस समस्या से बच सकते हैं जो रनटाइम त्रुटियों का कारण बन सकती है (और हम उन्हें नहीं चाहते हैं!)
protocol JSONDecodable {
associatedtype Element
static func from(_ json: [String: Any]) -> Element?
}
struct TestObject: JSONDecodable {
static func from(_ json: [String: Any]) -> TestObject? {
}
}
let testObject = TestObject.from(myJson) // testObject is now automatically `TestObject?`
उन्नत प्रकार की बाधाएँ
where
क्लॉज का उपयोग करके जेनरिक के लिए कई प्रकार की बाधाओं को निर्दिष्ट करना संभव है:
func doSomething<T where T: Comparable, T: Hashable>(first: T, second: T) {
// Access hashable function
guard first.hashValue == second.hashValue else {
return
}
// Access comparable function
if first == second {
print("\(first) and \(second) are equal.")
}
}
यह तर्क सूची के बाद where
खंड लिखने के लिए भी मान्य है:
func doSomething<T>(first: T, second: T) where T: Comparable, T: Hashable {
// Access hashable function
guard first.hashValue == second.hashValue else {
return
}
// Access comparable function
if first == second {
print("\(first) and \(second) are equal.")
}
}
स्थितियों को संतुष्ट करने वाले प्रकारों तक ही सीमित रखा जा सकता है। फ़ंक्शन केवल उन उदाहरणों के लिए उपलब्ध है जो प्रकार की स्थितियों को संतुष्ट करते हैं:
// "Element" is the generics type defined by "Array". For this example, we
// want to add a function that requires that "Element" can be compared, that
// is: it needs to adhere to the Equatable protocol.
public extension Array where Element: Equatable {
/// Removes the given object from the array.
mutating func remove(_ element: Element) {
// We could also use "self.index(of: element)" here, as "index(of:_)"
// is also defined in an extension with "where Element: Equatable".
// For the sake of this example, explicitly make use of the Equatable.
if let index = self.index(where: { $0 == element }) {
self.remove(at: index)
} else {
fatalError("Removal error, no such element:\"\(element)\" in array.\n")
}
}
}