खोज…


टिप्पणियों

जेनेरिक कोड आपको लचीले, पुन: प्रयोज्य कार्यों और प्रकारों को लिखने में सक्षम बनाता है जो आपके द्वारा परिभाषित आवश्यकताओं के अधीन किसी भी प्रकार के साथ काम कर सकते हैं। आप ऐसा कोड लिख सकते हैं जो दोहराव से बचता है और अपने इरादे को स्पष्ट, अमूर्त तरीके से व्यक्त करता है।

जेनेटिक्स स्विफ्ट की सबसे शक्तिशाली विशेषताओं में से एक है, और स्विफ्ट मानक पुस्तकालय का अधिकांश हिस्सा जेनेरिक कोड के साथ बनाया गया है। उदाहरण के लिए, स्विफ्ट के 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")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow