একটি সুইফট ট্যুর

পরিবর্তন সহ Swift.org- এ মূল A Swift Tour থেকে অভিযোজিত। আসল বিষয়বস্তু 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 । অন্যথায়, ঐচ্ছিক মান unwrapped, এবং সবকিছু পরে ? unwrapped মান উপর কাজ করে। উভয় ক্ষেত্রেই, সমগ্র অভিব্যক্তির মান একটি ঐচ্ছিক মান।

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.

ডিফল্টরূপে, সুইফট শূন্য থেকে শুরু করে কাঁচা মান নির্ধারণ করে এবং প্রতিবার একটি করে বৃদ্ধি করে, তবে আপনি স্পষ্টভাবে মান উল্লেখ করে এই আচরণ পরিবর্তন করতে পারেন। উপরের উদাহরণে, Ace-কে স্পষ্টভাবে 1 এর একটি কাঁচা মান দেওয়া হয়েছে, এবং বাকি কাঁচা মানগুলি ক্রম অনুসারে বরাদ্দ করা হয়েছে। আপনি একটি গণনার কাঁচা প্রকার হিসাবে স্ট্রিং বা ফ্লোটিং-পয়েন্ট সংখ্যাগুলিও ব্যবহার করতে পারেন। একটি গণনার ক্ষেত্রে কাঁচা মান অ্যাক্সেস করতে rawValue বৈশিষ্ট্য ব্যবহার করুন।

একটি কাঁচা মান থেকে একটি গণনার একটি উদাহরণ তৈরি করতে init?(rawValue:) ইনিশিয়ালাইজার ব্যবহার করুন। এটি হয় কাঁচা মানের সাথে মিলে যাওয়া গণনার ক্ষেত্রে বা nil প্রদান করে যদি কোনো মিলিত Rank না থাকে।

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