एक स्विफ्ट टूर

संशोधनों के साथ स्विफ्ट.ओआरजी पर मूल ए स्विफ्ट टूर से अनुकूलित। मूल सामग्री Apple Inc. द्वारा क्रिएटिव कॉमन्स एट्रिब्यूशन 4.0 इंटरनेशनल (CC BY 4.0) लाइसेंस के तहत लाइसेंस प्राप्त द्वारा लिखी गई थी।
TensorFlow.org पर देखें Google Colab में चलाएँ GitHub पर स्रोत देखें

परंपरा से पता चलता है कि किसी नई भाषा के पहले प्रोग्राम में "हैलो, वर्ल्ड!" शब्द मुद्रित होने चाहिए। स्क्रीन पर. स्विफ्ट में, यह एक ही पंक्ति में किया जा सकता है:

print("Hello, world!")
Hello, world!

यदि आपने सी या ऑब्जेक्टिव-सी में कोड लिखा है, तो यह सिंटैक्स आपको परिचित लगता है - स्विफ्ट में, कोड की यह पंक्ति एक संपूर्ण प्रोग्राम है। आपको इनपुट/आउटपुट या स्ट्रिंग हैंडलिंग जैसी कार्यक्षमता के लिए एक अलग लाइब्रेरी आयात करने की आवश्यकता नहीं है। वैश्विक दायरे में लिखे गए कोड का उपयोग प्रोग्राम के लिए प्रवेश बिंदु के रूप में किया जाता है, इसलिए आपको main() फ़ंक्शन की आवश्यकता नहीं होती है। आपको प्रत्येक कथन के अंत में अर्धविराम लिखने की भी आवश्यकता नहीं है।

यह टूर आपको विभिन्न प्रकार के प्रोग्रामिंग कार्यों को पूरा करने का तरीका दिखाकर स्विफ्ट में कोड लिखना शुरू करने के लिए पर्याप्त जानकारी देता है। अगर आपको कुछ समझ में नहीं आता है तो चिंता न करें—इस दौरे में पेश की गई हर चीज़ इस पुस्तक के बाकी हिस्सों में विस्तार से बताई गई है।

सरल मूल्य

एक स्थिरांक बनाने के लिए let उपयोग करें और एक चर बनाने के लिए var उपयोग करें। किसी स्थिरांक के मान को संकलन समय पर जानने की आवश्यकता नहीं है, लेकिन आपको इसे ठीक एक बार मान निर्दिष्ट करना होगा। इसका मतलब यह है कि आप किसी मान को नाम देने के लिए स्थिरांक का उपयोग कर सकते हैं जिसे आप एक बार निर्धारित करते हैं लेकिन कई स्थानों पर उपयोग करते हैं।

var myVariable = 42
myVariable = 50
let myConstant = 42

किसी स्थिरांक या चर का प्रकार वही होना चाहिए जो मान आप उसे निर्दिष्ट करना चाहते हैं। हालाँकि, आपको हमेशा प्रकार को स्पष्ट रूप से लिखने की ज़रूरत नहीं है। जब आप कोई स्थिरांक या चर बनाते हैं तो एक मान प्रदान करने से कंपाइलर उसके प्रकार का अनुमान लगा सकता है। उपरोक्त उदाहरण में, कंपाइलर अनुमान लगाता है कि myVariable एक पूर्णांक है क्योंकि इसका प्रारंभिक मान एक पूर्णांक है।

यदि प्रारंभिक मान पर्याप्त जानकारी प्रदान नहीं करता है (या यदि कोई प्रारंभिक मान नहीं है), तो इसे वेरिएबल के बाद कोलन द्वारा अलग करके लिखकर प्रकार निर्दिष्ट करें। नोट: फ़्लोटिंग पॉइंट नंबरों के लिए Float के बजाय Double उपयोग करने से आपको अधिक सटीकता मिलती है, और यह स्विफ्ट में डिफ़ॉल्ट फ़्लोटिंग पॉइंट प्रकार है।

let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
// Experiment:
// Create a constant with an explicit type of `Float` and a value of 4.

मानों को कभी भी किसी अन्य प्रकार में अंतर्निहित रूप से परिवर्तित नहीं किया जाता है। यदि आपको किसी मान को किसी भिन्न प्रकार में परिवर्तित करने की आवश्यकता है, तो स्पष्ट रूप से वांछित प्रकार का एक उदाहरण बनाएं।

let label = "The width is "
let width = 94
print(label + String(width))
The width is 94

// Experiment:
// Try removing the conversion to `String` from the last line. What error do you get?

स्ट्रिंग्स में मान शामिल करने का एक और भी सरल तरीका है: मान को कोष्ठक में लिखें, और कोष्ठक से पहले एक बैकस्लैश (``) लिखें। उदाहरण के लिए:

let apples = 3
print("I have \(apples) apples.")
I have 3 apples.

let oranges = 5
print("I have \(apples + oranges) pieces of fruit.")
I have 8 pieces of fruit.

// Experiment:
// Use `\()` to include a floating-point calculation in a string and to include someone's name in a
// greeting.

एकाधिक पंक्तियाँ लेने वाली स्ट्रिंग्स के लिए तीन दोहरे उद्धरण चिह्नों ( """ ) का उपयोग करें। प्रत्येक उद्धृत पंक्ति की शुरुआत में इंडेंटेशन हटा दिया जाता है, जब तक कि यह समापन उद्धरण चिह्नों के इंडेंटेशन से मेल खाता है। उदाहरण के लिए:

let quotation = """
    Even though there's whitespace to the left,
    the actual lines aren't indented.
        Except for this line.
    Double quotes (") can appear without being escaped.

    I still have \(apples + oranges) pieces of fruit.
    """
print(quotation)
Even though there's whitespace to the left,
the actual lines aren't indented.
    Except for this line.
Double quotes (") can appear without being escaped.

I still have 8 pieces of fruit.

कोष्ठक ( [] ) का उपयोग करके सारणी और शब्दकोश बनाएं, और कोष्ठक में सूचकांक या कुंजी लिखकर उनके तत्वों तक पहुंचें। अंतिम तत्व के बाद अल्पविराम की अनुमति है।

var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
print(occupations)
["Jayne": "Public Relations", "Kaylee": "Mechanic", "Malcolm": "Captain"]

जैसे ही आप तत्व जोड़ते हैं, सारणियाँ स्वचालित रूप से बढ़ती हैं।

shoppingList.append("blue paint")
print(shoppingList)
["catfish", "bottle of water", "tulips", "blue paint", "blue paint"]

एक खाली सरणी या शब्दकोश बनाने के लिए, इनिशियलाइज़र सिंटैक्स का उपयोग करें।

let emptyArray = [String]()
let emptyDictionary = [String: Float]()

यदि प्रकार की जानकारी का अनुमान लगाया जा सकता है, तो आप एक खाली सरणी को [] के रूप में और एक खाली शब्दकोश को [:] के रूप में लिख सकते हैं - उदाहरण के लिए, जब आप किसी वेरिएबल के लिए एक नया मान सेट करते हैं या किसी फ़ंक्शन में तर्क पास करते हैं।

shoppingList = []
occupations = [:]

प्रवाह को नियंत्रित करें

सशर्त बनाने के लिए if और switch उपयोग करें, और लूप बनाने के लिए for - in , for , while , और repeat - while उपयोग करें। स्थिति या लूप वेरिएबल के चारों ओर कोष्ठक वैकल्पिक हैं। शरीर के चारों ओर ब्रेसिज़ की आवश्यकता होती है।

let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
print(teamScore)
11

if कथन में, सशर्त एक बूलियन अभिव्यक्ति होनी चाहिए - इसका मतलब है कि कोड जैसे कि if score { ... } एक त्रुटि है, शून्य के साथ एक अंतर्निहित तुलना नहीं है।

आप उन मूल्यों के साथ काम करने के लिए if और let एक साथ उपयोग कर सकते हैं जो गायब हो सकते हैं। इन मानों को वैकल्पिक के रूप में दर्शाया गया है। एक वैकल्पिक मान में या तो एक मान होता है या nil होता है जो दर्शाता है कि कोई मान गायब है। मान को वैकल्पिक के रूप में चिह्नित करने के लिए मान के प्रकार के बाद एक प्रश्न चिह्न ( ? ) लिखें।

var optionalString: String? = "Hello"
print(optionalString == nil)
false

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
print(greeting)
Hello, John Appleseed

// Experiment:
// Change `optionalName` to `nil`. What greeting do you get?
// Add an `else` clause that sets a different greeting if `optionalName` is `nil`.

यदि वैकल्पिक मान nil है, तो सशर्त false है और ब्रेसिज़ में कोड छोड़ दिया गया है। अन्यथा, वैकल्पिक मान को अनरैप किया जाता है और let बाद स्थिरांक को सौंपा जाता है, जो कोड के ब्लॉक के अंदर अनरैप किए गए मान को उपलब्ध कराता है।

वैकल्पिक मानों को संभालने का दूसरा तरीका ?? का उपयोग करके एक डिफ़ॉल्ट मान प्रदान करना है। ऑपरेटर. यदि वैकल्पिक मान अनुपलब्ध है, तो इसके स्थान पर डिफ़ॉल्ट मान का उपयोग किया जाता है।

let nickName: String? = nil
let fullName: String = "John Appleseed"
print("Hi \(nickName ?? fullName)")
Hi John Appleseed

स्विच किसी भी प्रकार के डेटा और विभिन्न प्रकार के तुलना संचालन का समर्थन करते हैं - वे पूर्णांक और समानता के परीक्षणों तक सीमित नहीं हैं।

let vegetable = "red pepper"
switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}
Is it a spicy red pepper?

// Experiment:
// Try removing the default case. What error do you get?

ध्यान दें कि किसी पैटर्न में किसी स्थिरांक से मेल खाने वाले मान को असाइन करने के लिए let उपयोग कैसे किया जा सकता है।

स्विच केस के अंदर मेल खाने वाले कोड को निष्पादित करने के बाद, प्रोग्राम स्विच स्टेटमेंट से बाहर निकल जाता है। निष्पादन अगले मामले तक जारी नहीं रहता है, इसलिए प्रत्येक मामले के कोड के अंत में स्विच को स्पष्ट रूप से तोड़ने की कोई आवश्यकता नहीं है।

आप प्रत्येक कुंजी-मूल्य जोड़ी के लिए उपयोग करने के लिए नामों की एक जोड़ी प्रदान करके शब्दकोश में आइटमों को पुनरावृत्त करने के लिए for - in का उपयोग करते हैं। शब्दकोश एक अव्यवस्थित संग्रह है, इसलिए उनकी कुंजियाँ और मान एक मनमाने क्रम में दोहराए जाते हैं।

let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
print(largest)
25

// Experiment:
// Add another variable to keep track of which kind of number was the largest, as well as what that
// largest number was.

जब तक कोई स्थिति न बदल जाए तब तक कोड के एक ब्लॉक को दोहराने के लिए while उपयोग करें। लूप की स्थिति इसके बजाय अंत में हो सकती है, यह सुनिश्चित करते हुए कि लूप कम से कम एक बार चलाया जाए।

var n = 2
while n < 100 {
    n = n * 2
}

print(n)
128

var m = 2
repeat {
    m = m * 2
} while m < 100

print(m)
128

आप एक इंडेक्स को लूप में रख सकते हैं - या तो इंडेक्स की एक श्रृंखला बनाने के लिए ..< का उपयोग करके या एक स्पष्ट आरंभीकरण, स्थिति और वृद्धि लिखकर। ये दो लूप एक ही काम करते हैं:

var total = 0
for i in 0..<4 {
    total += i
}

print(total)
6

ऐसी श्रेणी बनाने के लिए ..< उपयोग करें जो इसके ऊपरी मान को छोड़ देती है, और ... का उपयोग ऐसी श्रेणी बनाने के लिए करें जिसमें दोनों मान शामिल हों।

कार्य और समापन

किसी फ़ंक्शन को घोषित करने के लिए func उपयोग करें। कोष्ठक में तर्कों की सूची के साथ किसी फ़ंक्शन के नाम का अनुसरण करके उसे कॉल करें। फ़ंक्शन के रिटर्न प्रकार से पैरामीटर नाम और प्रकार को अलग करने के लिए -> उपयोग करें।

func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
print(greet(name: "Bob", day: "Tuesday"))
Hello Bob, today is Tuesday.

// Experiment:
// Remove the `day` parameter. Add a parameter to include today’s lunch special in the greeting.

डिफ़ॉल्ट रूप से, फ़ंक्शन अपने तर्कों के लिए लेबल के रूप में अपने पैरामीटर नामों का उपयोग करते हैं। पैरामीटर नाम से पहले एक कस्टम तर्क लेबल लिखें, या बिना तर्क लेबल का उपयोग करने के लिए _ लिखें।

func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
print(greet("John", on: "Wednesday"))
Hello John, today is Wednesday.

एक यौगिक मान बनाने के लिए टुपल का उपयोग करें - उदाहरण के लिए, किसी फ़ंक्शन से एकाधिक मान वापस करने के लिए। टुपल के तत्वों को नाम या संख्या से संदर्भित किया जा सकता है।

func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0

    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }

    return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)
120
120

फ़ंक्शंस को नेस्ट किया जा सकता है. नेस्टेड फ़ंक्शंस के पास वेरिएबल्स तक पहुंच होती है जो बाहरी फ़ंक्शन में घोषित किए गए थे। आप लंबे या जटिल फ़ंक्शन में कोड को व्यवस्थित करने के लिए नेस्टेड फ़ंक्शन का उपयोग कर सकते हैं।

func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
print(returnFifteen())
15

फ़ंक्शंस प्रथम श्रेणी प्रकार हैं। इसका मतलब यह है कि एक फ़ंक्शन किसी अन्य फ़ंक्शन को उसके मान के रूप में लौटा सकता है।

func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
print(increment(7))
8

एक फ़ंक्शन किसी अन्य फ़ंक्शन को अपने तर्कों में से एक के रूप में ले सकता है।

func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
print(hasAnyMatches(list: numbers, condition: lessThanTen))
true

फ़ंक्शंस वास्तव में क्लोजर का एक विशेष मामला है: कोड के ब्लॉक जिन्हें बाद में कॉल किया जा सकता है। क्लोजर में कोड के पास वेरिएबल्स और फ़ंक्शंस जैसी चीज़ों तक पहुंच होती है जो उस दायरे में उपलब्ध थे जहां क्लोजर बनाया गया था, भले ही क्लोजर निष्पादित होने पर एक अलग दायरे में हो - आपने नेस्टेड फ़ंक्शंस के साथ इसका एक उदाहरण पहले से ही देखा है। आप ब्रेसिज़ ( {} ) के साथ कोड को घेरकर बिना नाम के क्लोजर लिख सकते हैं। तर्कों और रिटर्न प्रकार को मुख्य भाग से अलग करने के लिए in उपयोग करें।

let mappedNumbers = numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})
print(mappedNumbers)
[60, 57, 21, 36]

// Experiment:
// Rewrite the closure to return zero for all odd numbers.

समापन को अधिक संक्षेप में लिखने के लिए आपके पास कई विकल्प हैं। जब क्लोजर का प्रकार पहले से ही ज्ञात हो, जैसे किसी प्रतिनिधि के लिए कॉलबैक, तो आप इसके पैरामीटर के प्रकार, इसके रिटर्न प्रकार, या दोनों को छोड़ सकते हैं। एकल कथन समापन परोक्ष रूप से उनके एकमात्र कथन का मान लौटाता है।

let mappedNumbers2 = numbers.map({ number in 3 * number })
print(mappedNumbers2)
[60, 57, 21, 36]

आप पैरामीटर को नाम के बजाय संख्या के आधार पर संदर्भित कर सकते हैं - यह दृष्टिकोण विशेष रूप से बहुत कम समापन में उपयोगी है। किसी फ़ंक्शन के अंतिम तर्क के रूप में पारित समापन कोष्ठक के तुरंत बाद दिखाई दे सकता है। जब किसी फ़ंक्शन के लिए क्लोजर ही एकमात्र तर्क होता है, तो आप कोष्ठकों को पूरी तरह से हटा सकते हैं।

let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
[20, 19, 12, 7]

वस्तुएँ और वर्ग

क्लास बनाने के लिए क्लास के नाम के बाद class का उपयोग करें। किसी वर्ग में संपत्ति घोषणा को स्थिर या परिवर्तनीय घोषणा के समान ही लिखा जाता है, सिवाय इसके कि यह एक वर्ग के संदर्भ में है। इसी तरह, विधि और फ़ंक्शन घोषणाएँ भी उसी तरह लिखी जाती हैं।

class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
// Experiment:
// Add a constant property with `let`, and add another method that takes an argument.

कक्षा के नाम के बाद कोष्ठक लगाकर कक्षा का एक उदाहरण बनाएं। उदाहरण के गुणों और विधियों तक पहुँचने के लिए डॉट सिंटैक्स का उपयोग करें।

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

Shape क्लास के इस संस्करण में कुछ महत्वपूर्ण कमी है: एक इंस्टेंस बनाते समय क्लास को सेट करने के लिए एक इनिशियलाइज़र। एक बनाने के लिए init उपयोग करें।

class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

ध्यान दें कि name गुण को name तर्क से प्रारंभकर्ता तक अलग करने के लिए self उपयोग कैसे किया जाता है। जब आप क्लास का एक उदाहरण बनाते हैं तो इनिशियलाइज़र के तर्क एक फ़ंक्शन कॉल की तरह पारित किए जाते हैं। प्रत्येक संपत्ति को एक मान निर्दिष्ट करने की आवश्यकता होती है - या तो उसकी घोषणा में (जैसा कि numberOfSides के साथ) या आरंभकर्ता में (जैसा कि name के साथ)।

यदि आपको ऑब्जेक्ट के आवंटित होने से पहले कुछ सफाई करने की आवश्यकता है, तो डीइनिशियलाइज़र बनाने के लिए deinit उपयोग करें।

उपवर्गों में उनके वर्ग के नाम के बाद एक कोलन द्वारा अलग किया गया उनका सुपरक्लास नाम शामिल होता है। कक्षाओं के लिए किसी भी मानक रूट क्लास को उपवर्गित करने की कोई आवश्यकता नहीं है, इसलिए आप आवश्यकतानुसार सुपरक्लास को शामिल या हटा सकते हैं।

सुपरक्लास के कार्यान्वयन को ओवरराइड करने वाले उपवर्ग के तरीकों को override के साथ चिह्नित किया जाता है - override के बिना, दुर्घटनावश किसी विधि को ओवरराइड करना, कंपाइलर द्वारा एक त्रुटि के रूप में पता लगाया जाता है। कंपाइलर override वाले तरीकों का भी पता लगाता है जो वास्तव में सुपरक्लास में किसी भी विधि को ओवरराइड नहीं करते हैं।

class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
print(test.area())
print(test.simpleDescription())
27.040000000000003
A square with sides of length 5.2.

// Experiment:
// - Make another subclass of `NamedShape` called `Circle` that takes a radius and a name as
//   arguments to its initializer.
// - Implement an `area()` and a `simpleDescription()` method on the `Circle` class.

संग्रहीत सरल गुणों के अलावा, गुणों में एक गेटर और एक सेटर हो सकता है।

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }

    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
9.3
3.3000000000000003

perimeter के लिए सेटर में, नए मान का अंतर्निहित नाम newValue है। आप set के बाद कोष्ठक में एक स्पष्ट नाम प्रदान कर सकते हैं।

ध्यान दें कि EquilateralTriangle वर्ग के प्रारंभकर्ता के तीन अलग-अलग चरण हैं:

  1. उपवर्ग द्वारा घोषित गुणों का मूल्य निर्धारित करना।

  2. सुपरक्लास के इनिशियलाइज़र को कॉल करना।

  3. सुपरक्लास द्वारा परिभाषित गुणों का मूल्य बदलना। कोई भी अतिरिक्त सेटअप कार्य जो विधियों, गेटर्स या सेटर्स का उपयोग करता है, इस बिंदु पर भी किया जा सकता है।

यदि आपको संपत्ति की गणना करने की आवश्यकता नहीं है, लेकिन फिर भी आपको नया मान सेट करने से पहले और बाद में चलने वाला कोड प्रदान करने की आवश्यकता है, तो willSet और didSet उपयोग करें। आपके द्वारा प्रदान किया गया कोड किसी भी समय इनिशियलाइज़र के बाहर मान बदलने पर चलाया जाता है। उदाहरण के लिए, नीचे दिया गया वर्ग यह सुनिश्चित करता है कि उसके त्रिभुज की भुजा की लंबाई हमेशा उसके वर्ग की भुजा की लंबाई के समान हो।

class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            triangle.sideLength = newValue.sideLength
        }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
10.0
10.0
50.0

वैकल्पिक मानों के साथ काम करते समय, आप लिख सकते हैं ? विधियों, गुणों और सबस्क्रिप्टिंग जैसे संचालन से पहले। यदि इससे पहले का मान ? nil है, के बाद सब कुछ ? अनदेखा कर दिया गया है और संपूर्ण अभिव्यक्ति का मान nil है। अन्यथा, वैकल्पिक मान को हटा दिया जाता है, और ? के बाद की सभी चीज़ें हटा दी जाती हैं। अलिखित मूल्य पर कार्य करता है। दोनों ही मामलों में, संपूर्ण अभिव्यक्ति का मान एक वैकल्पिक मान है।

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
print(optionalSquare?.sideLength)
Optional(2.5)

गणना और संरचनाएँ

गणना बनाने के लिए enum उपयोग करें। कक्षाओं और अन्य सभी नामित प्रकारों की तरह, गणनाओं में उनसे जुड़ी विधियाँ हो सकती हैं।

enum Rank: Int {
    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king

    func simpleDescription() -> String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}
let ace = Rank.ace
print(ace)
let aceRawValue = ace.rawValue
print(aceRawValue)
ace
1

// Experiment:
// Write a function that compares two `Rank` values by comparing their raw values.

डिफ़ॉल्ट रूप से, स्विफ्ट शून्य से शुरू होने वाले और हर बार एक बढ़ते हुए कच्चे मान निर्दिष्ट करती है, लेकिन आप स्पष्ट रूप से मान निर्दिष्ट करके इस व्यवहार को बदल सकते हैं। उपरोक्त उदाहरण में, ऐस को स्पष्ट रूप से 1 का कच्चा मान दिया गया है, और शेष कच्चे मान क्रम में निर्दिष्ट किए गए हैं। आप गणना के मूल प्रकार के रूप में स्ट्रिंग्स या फ़्लोटिंग-पॉइंट संख्याओं का भी उपयोग कर सकते हैं। गणना मामले के कच्चे मूल्य तक पहुंचने के लिए rawValue प्रॉपर्टी का उपयोग करें।

कच्चे मान से गणना का एक उदाहरण बनाने के लिए init?(rawValue:) इनिशियलाइज़र का उपयोग करें। यह या तो कच्चे मूल्य से मेल खाने वाला गणना मामला लौटाता है या यदि कोई मिलान Rank नहीं है तो nil लौटाता है।

if let convertedRank = Rank(rawValue: 3) {
    let threeDescription = convertedRank.simpleDescription()
}

किसी गणना के केस मान वास्तविक मान हैं, न कि उनके कच्चे मान लिखने का एक और तरीका। वास्तव में, ऐसे मामलों में जहां कोई सार्थक कच्चा मूल्य नहीं है, आपको एक प्रदान करने की आवश्यकता नहीं है।

enum Suit {
    case spades, hearts, diamonds, clubs

    func simpleDescription() -> String {
        switch self {
        case .spades:
            return "spades"
        case .hearts:
            return "hearts"
        case .diamonds:
            return "diamonds"
        case .clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
// Experiment:
// Add a `color()` method to `Suit` that returns "black" for spades and clubs, and returns "red" for
// hearts and diamonds.

उन दो तरीकों पर ध्यान दें जिनसे गणना के Hearts केस को ऊपर संदर्भित किया गया है: hearts स्थिरांक को एक मान निर्दिष्ट करते समय, एन्यूमरेशन केस Suit.Hearts को इसके पूर्ण नाम से संदर्भित किया जाता है क्योंकि स्थिरांक में कोई स्पष्ट प्रकार निर्दिष्ट नहीं होता है। स्विच के अंदर, गणना मामले को संक्षिप्त रूप .Hearts द्वारा संदर्भित किया जाता है क्योंकि self का मूल्य पहले से ही एक सूट के रूप में जाना जाता है। जब भी मान का प्रकार पहले से ज्ञात हो तो आप संक्षिप्त रूप का उपयोग कर सकते हैं।

यदि किसी गणना में कच्चे मूल्य हैं, तो उन मूल्यों को घोषणा के हिस्से के रूप में निर्धारित किया जाता है, जिसका अर्थ है कि किसी विशेष गणना मामले के प्रत्येक उदाहरण में हमेशा एक ही कच्चा मूल्य होता है। गणना मामलों के लिए एक अन्य विकल्प मामले से जुड़े मूल्यों का होना है - ये मान तब निर्धारित होते हैं जब आप उदाहरण बनाते हैं, और वे गणना मामले के प्रत्येक उदाहरण के लिए भिन्न हो सकते हैं। आप संबंधित मूल्यों को गणना मामले के उदाहरण के संग्रहीत गुणों की तरह व्यवहार करने के बारे में सोच सकते हैं।

उदाहरण के लिए, किसी सर्वर से सूर्योदय और सूर्यास्त के समय का अनुरोध करने के मामले पर विचार करें। सर्वर या तो अनुरोधित जानकारी के साथ प्रतिक्रिया देता है, या यह विवरण के साथ प्रतिक्रिया करता है कि क्या गलत हुआ।

enum ServerResponse {
    case result(String, String)
    case failure(String)
}

let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}
Sunrise is at 6:00 am and sunset is at 8:09 pm.

// Experiment:
// Add a third case to `ServerResponse` and to the switch.

ध्यान दें कि स्विच मामलों के विरुद्ध मान के मिलान के भाग के रूप में ServerResponse मान से सूर्योदय और सूर्यास्त का समय कैसे निकाला जाता है।

संरचना बनाने के लिए struct उपयोग करें। संरचनाएं कक्षाओं के समान कई व्यवहारों का समर्थन करती हैं, जिनमें विधियां और प्रारंभकर्ता शामिल हैं। संरचनाओं और कक्षाओं के बीच सबसे महत्वपूर्ण अंतरों में से एक यह है कि संरचनाओं को हमेशा तब कॉपी किया जाता है जब उन्हें आपके कोड में पास किया जाता है, लेकिन कक्षाएं संदर्भ द्वारा पारित की जाती हैं।

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
// Experiment:
// Write a function that returns an array containing a full deck of cards, with one card of each
// combination of rank and suit.

प्रोटोकॉल और एक्सटेंशन

प्रोटोकॉल घोषित करने के लिए protocol उपयोग करें।

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

कक्षाएं, गणनाएं और संरचनाएं सभी प्रोटोकॉल अपना सकती हैं।

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
print(b.adjust())
print(b.simpleDescription)
()
A simple structure (adjusted)

// Experiment:
// Add another requirement to `ExampleProtocol`.
// What changes do you need to make to `SimpleClass` and `SimpleStructure` so that they still
// conform to the protocol?

संरचना को संशोधित करने वाली विधि को चिह्नित करने के लिए SimpleStructure की घोषणा में mutating कीवर्ड के उपयोग पर ध्यान दें। SimpleClass की घोषणा के लिए इसके किसी भी तरीके को उत्परिवर्तन के रूप में चिह्नित करने की आवश्यकता नहीं है क्योंकि किसी वर्ग के तरीके हमेशा वर्ग को संशोधित कर सकते हैं।

किसी मौजूदा प्रकार में कार्यक्षमता जोड़ने के लिए extension उपयोग करें, जैसे नई विधियाँ और परिकलित गुण। आप किसी ऐसे प्रकार में प्रोटोकॉल अनुरूपता जोड़ने के लिए एक्सटेंशन का उपयोग कर सकते हैं जो कहीं और घोषित किया गया है, या यहां तक ​​कि उस प्रकार में भी जिसे आपने लाइब्रेरी या फ्रेमवर्क से आयात किया है।

extension Int: ExampleProtocol {
    public var simpleDescription: String {
        return "The number \(self)"
    }
    public mutating func adjust() {
        self += 42
    }
}
print(7.simpleDescription)
The number 7

// Experiment:
// Write an extension for the `Double` type that adds an `absoluteValue` property.

आप प्रोटोकॉल नाम का उपयोग किसी भी अन्य नामित प्रकार की तरह ही कर सकते हैं - उदाहरण के लिए, उन वस्तुओं का एक संग्रह बनाने के लिए जिनके विभिन्न प्रकार हैं लेकिन वे सभी एक ही प्रोटोकॉल के अनुरूप हैं। जब आप उन मानों के साथ काम करते हैं जिनका प्रकार एक प्रोटोकॉल प्रकार है, तो प्रोटोकॉल परिभाषा के बाहर के तरीके उपलब्ध नहीं होते हैं।

let protocolValue: ExampleProtocol = a
print(protocolValue.simpleDescription)
A very simple class.  Now 100% adjusted.

// Uncomment to see the error.
// protocolValue.anotherProperty

भले ही वेरिएबल protocolValue में SimpleClass का रनटाइम प्रकार है, कंपाइलर इसे दिए गए प्रकार के ExampleProtocol के रूप में मानता है। इसका मतलब यह है कि आप गलती से उन विधियों या गुणों तक नहीं पहुंच सकते हैं जो वर्ग अपने प्रोटोकॉल अनुरूपता के अतिरिक्त लागू करता है।

त्रुटि प्रबंधन

आप Error प्रोटोकॉल को अपनाने वाले किसी भी प्रकार का उपयोग करके त्रुटियों का प्रतिनिधित्व करते हैं।

enum PrinterError: Error {
    case outOfPaper
    case noToner
    case onFire
}

किसी त्रुटि को फेंकने के लिए throw उपयोग करें और किसी फ़ंक्शन को चिह्नित करने के लिए throws उपयोग करें जो त्रुटि उत्पन्न कर सकता है। यदि आप किसी फ़ंक्शन में कोई त्रुटि डालते हैं, तो फ़ंक्शन तुरंत वापस आ जाता है और फ़ंक्शन को कॉल करने वाला कोड त्रुटि को संभाल लेता है।

func send(job: Int, toPrinter printerName: String) throws -> String {
    if printerName == "Never Has Toner" {
        throw PrinterError.noToner
    }
    return "Job sent"
}

त्रुटियों से निपटने के कई तरीके हैं। एक तरीका do-catch उपयोग करना है। do ब्लॉक के अंदर, आप उस कोड को चिह्नित करते हैं जो उसके सामने प्रयास लिखकर त्रुटि उत्पन्न कर सकता है। catch ब्लॉक के अंदर, त्रुटि को स्वचालित रूप से error नाम दिया जाता है जब तक कि आप इसे एक अलग नाम नहीं देते।

do {
    let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
    print(printerResponse)
} catch {
    print(error)
}
Job sent

// Experiment:
// Change the printer name to `"Never Has Toner"`, so that the `send(job:toPrinter:)` function
// throws an error.

आप एकाधिक catch ब्लॉक प्रदान कर सकते हैं जो विशिष्ट त्रुटियों को संभालते हैं। आप catch के बाद एक पैटर्न लिखते हैं जैसे आप किसी स्विच में case के बाद लिखते हैं।

do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrinterError.onFire {
    print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}
Job sent

// Experiment:
// Add code to throw an error inside the `do` block.
// What kind of error do you need to throw so that the error is handled by the first `catch` block?
// What about the second and third blocks?

त्रुटियों को संभालने का दूसरा तरीका try? परिणाम को वैकल्पिक में बदलने के लिए। यदि फ़ंक्शन कोई त्रुटि देता है, तो विशिष्ट त्रुटि खारिज कर दी जाती है और परिणाम nil होता है। अन्यथा, परिणाम एक वैकल्पिक है जिसमें फ़ंक्शन द्वारा लौटाया गया मान शामिल है।

let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")

कोड के एक ब्लॉक को लिखने के लिए defer उपयोग करें जो फ़ंक्शन में अन्य सभी कोड के बाद, फ़ंक्शन के वापस आने से ठीक पहले निष्पादित होता है। कोड को इस पर ध्यान दिए बिना निष्पादित किया जाता है कि फ़ंक्शन कोई त्रुटि देता है या नहीं। आप सेटअप और क्लीनअप कोड को एक-दूसरे के बगल में लिखने के लिए defer उपयोग कर सकते हैं, भले ही उन्हें अलग-अलग समय पर निष्पादित करने की आवश्यकता हो।

var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        fridgeIsOpen = false
    }

    let result = fridgeContent.contains(food)
    return result
}
print(fridgeContains("banana"))
print(fridgeIsOpen)
false
false

जेनेरिक्स

सामान्य फ़ंक्शन या प्रकार बनाने के लिए कोण कोष्ठक के अंदर एक नाम लिखें।

func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
    var result = [Item]()
    for _ in 0..<numberOfTimes {
        result.append(item)
    }
    return result
}
print(makeArray(repeating: "knock", numberOfTimes: 4))
["knock", "knock", "knock", "knock"]

आप फ़ंक्शंस और विधियों के सामान्य रूप, साथ ही कक्षाएं, गणना और संरचनाएं बना सकते हैं।

// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
print(possibleInteger)
some(100)

आवश्यकताओं की सूची निर्दिष्ट करने के लिए प्रकार के नाम के बाद where उपयोग करें - उदाहरण के लिए, किसी प्रोटोकॉल को लागू करने के लिए प्रकार की आवश्यकता होती है, दो प्रकार समान होने की आवश्यकता होती है, या किसी वर्ग के लिए एक विशेष सुपरक्लास की आवश्यकता होती है।

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
    where T.Element: Equatable, T.Element == U.Element
{
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
print(anyCommonElements([1, 2, 3], [3]))
true

<T: Equatable> लिखना <T> ... where T: Equatable