Generic (জেনারিক প্রোগ্রামিং) — Swift এর একটি প্রক্রিয়া যা প্যারামিটারাইজড টাইপ
মূল বিষয়সমূহ
Generic (জেনারিক টাইপ) — Swift এর একটি ব্যাকরণিক গঠন যা টাইপ প্যারামিটারাইজেশন সহ নমনীয়, পুনর্ব্যবহার্য কোড লেখার অনুমতি দেয়। একটি নির্দিষ্ট টাইপের পরিবর্তে, কোণাকার ব্র্যাকেটে একটি প্লেসহোল্ডার লেখা হয় — সাধারণত
জেনারিক্স ছাড়া, আপনাকে প্রতিটি টাইপের জন্য পৃথক ফাংশন লিখতে হবে: swapInts, swapStrings, swapDates । একটি generic swap ফাংশন একটি ঘোষণার মাধ্যমে তিনটি ভ্যারিয়েন্টকে প্রতিস্থাপন করে। এটি দুবারের পরিমাণ হ্রাস করে, পড়ার সুবিধা বাড়ায় ও কোড কপি করার সময় ত্রুটির সম্ভাবনা হ্রাস করে।
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var x = 10
var y = 20
swapValues(&x, &y)
Swift কম্পাইলার generic এর প্রতিটি নির্দিষ্ট ব্যবহারের জন্য বিশেষায়ন কোড উত্পাদন করে। এর মানে হল generic ফাংশন swapValues
জেনারিক ফাংশন হল যে ফাংশন এক বা একাধিক টাইপ প্যারামিটার গ্রহণ করে। টাইপ প্যারামিটার ফাংশনের নামের পর কোণাকার ব্র্যাকেটে নির্দিষ্ট করা হয়:
একটি ফাংশনের একাধিক generic প্যারামিটার থাকতে পারে। উদাহরণস্বরূপ, ফাংশন findKey
func findKey<K: Hashable, V>(
for value: V,
in dictionary: [K: V]
) -> K? where V: Equatable {
for (key, dictValue) in dictionary {
if dictValue == value {
return key
}
}
return nil
}
সীমাবদ্ধি K: Hashable ও where V: Equatable নিশ্চিত করে যে findKey কেবল এমন একটি অভিধানের সাথে ডাকা যেতে পারে যার চাবি হ্যাশেবল ও মান ইক্যুইটেবল । এমন সীমাবদ্ধি আমলতন্ত্র নয়, বরং অপরিহার্য: Hashable ছাড়া আপনি চাবি অনুসন্ধান ইনডেক্স করতে পারবেন না, Equatable ছাড়া আপনি dictValue এর সাথে value তুলনা করতে পারবেন না।
where — Swift এর একটি কীওয়ার্ড যা generic প্যারামিটারের উপর অতিরিক্ত সীমাবদ্ধি বেশ করে। কোণাকার ব্র্যাকেট (
where ক্লজ় ফাংশন বা টাইপের সিগনেচারের পরে, খুলনা ব্রেসের আগে লেখা হয়। where এ আপনি নির্দিষ্ট করতে পারেন যে T: Comparable & Hashable (একটি সাথে দুটি প্রোটোকলের অনুসরণ করে), বা T.U == Int (একটি সংশ্লিষ্ট টাইপ নির্দিষ্ট করে)।
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
}
extension Container where Item: Comparable {
func isSorted() -> Bool {
// Implementation available only if Item: Comparable
return true
}
}
where সহ এক্সটেনশন কেবল সেই টাইপগুলোর জন্য পদ্ধতি যোগ করে যারা শর্ত পূরণ করে। Container
Associated Types (সংশ্লিষ্ট টাইপ) — একটি প্রোটোকলকে ঘোষণার সময় নির্দিষ্ট টাইপ উল্লেখ না করে জেনারিক করার একটি উপায়।
where ব্যবহার করে আপনি বিভিন্ন প্রোটোকলের associated types এর মধ্যে সম্পর্ক স্থাপনা করতে পারেন। উদাহরণস্বরূপ, আপনি দাবি করতে পারেন যে একটি প্রোটোকলের Item অন্যটির Iterator.Element এর সাথে মেলাছে। এটি কম্পাইলার স্তরে টাইপ সামঞ্জস্য নিশ্চিত করে।
protocol StackProtocol {
associatedtype Element
mutating func push(_ item: Element)
mutating func pop() -> Element?
}
struct IntStack: StackProtocol {
typealias Element = Int
private var items: [Int] = []
mutating func push(_ item: Int) { items.append(item) }
mutating func pop() -> Int? { items.popLast() }
}
IntStack typealias ব্যবহার করে Element কে Int হিসাবে নির্দিষ্ট করে। কম্পাইলার যাচাই করে যে এই টাইপের সাথে প্রোটোকলের সকল আবশ্যকতা পূরণ হয়। associated types ছাড়া, আপনাকে একটি generic প্রোটোকলের সাথে StackProtocol
Generic এক্সটেনশন অতিরিক্ত সীমাবদ্ধি সহ একটি generic টাইপে পদ্ধতি যোগ করার অনুমতি দেয়। এটি হল শর্তমূলক অনুরূপণ পৈটার্ন, যেখানে একটি টাইপ কেবল নির্দিষ্ট শর্তে কার্যকারিতা পায়। সাবস্ক্রিপ্ট ও generic হতে পারে।
একটি সাবস্ক্রিপ্ট generic হতে পারে: এটি কোণাকার ব্র্যাকেটে generic প্যারামিটার গ্রহণ করে। এটি এমন কর্বনাপসন্দ ইনডেক্স সহ সংগ্রহে নিরাপদ প্রবেশের জন্য উপযোগী, যেখানে ইনডেক্স বিভিন্ন টাইপের হতে পারে।
extension Array where Element: Numeric {
func sum() -> Element {
return reduce(0, +)
}
}
extension Array {
subscript<Indices: Sequence>(indices: Indices) -> [Element]
where Indices.Element == Int {
return indices.map { self[$0] }
}
}
এই গঠন শক্তিশালী কম্পোজিশন প্রদান করে: sum পদ্ধতি কেবল সংখ্যামূলক অ্যারেতে উপস্থিত হয়, এবং কর্বনাপসন্দ ইনডেক্স সহ সাবস্ক্রিপ্ট পূর্ণাংক ইনডেক্সের যে কোনো অনুক্রমের সাথে কাজ করে। কম্পাইলার where শর্তের উপর ভিত্তি করে এই সদস্যগুলির দৃশ্যমানতা নিয়ন্ত্রণ করে।
ভুল generic ব্যবহার করার সময় প্রায়ই ভুল সীমাবদ্ধি বা যেখানে নির্দিষ্ট টাইপ প্রয়োজন সেখানে generic ব্যবহারের চেষ্টার সাথে সম্পর্কিত। আসুন তিনটি সাধারণ পরিদৃশ্য দেখি যা ডিভেলপারদের সমাধান করতে হয়।
যেখানে নির্দিষ্ট টাইপ যথেষ্ট সেখানে generic প্যারামিটার যোগ করা একটি অনাতস্ব নমুনা। যদি একটি ফাংশন সব সময় String নিয়ে কাজ করে, তবে এটিকে
একটি generic প্যারামিটারে একটি পদ্ধতি কেল করা যে পদ্ধতিটি বিদ্যমান তা নির্দিষ্ট না করে একটি ত্রুটি।
// ❌ Error: value has no count method
func countElements<T>>(value: T) -> Int { value.count }
// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }
ত্রুটিটি স্পষ্ট: generic
সাধারণজিজ্ঞাসিত প্রশ্ন
Generic হল কোড লেখার একটি উপায় যা যে কোনো টাইপের সাথে কাজ করে, Int, String ও অন্যান্য টাইপের জন্য একই যুক্তি দুবার না করে। একটি নির্দিষ্ট টাইপের পরিবর্তে, একটি প্লেসহোল্ডার
Generic কম্পাইল টাইমে নির্দিষ্ট টাইপের তথ্য সংরক্ষণ করে, যা কম্পাইলারকে টাইপ যাচাই ও অপ্টিমাইজড কোড উত্পাদনের অনুমতি দেয়। Any হল টাইপ ইরেজার: যে কোনো মান পাস করা যেতে পারে, কিন্তু টাইপ হারিয়ে যায় ও কাস্টিং (as?) প্রয়োজন।
কোণাকার ব্র্যাকেটে T: SomeProtocol সিনট্যাক্স বা একটি পৃথক ক্লজ় where T: SomeProtocol ব্যবহার করুন। সীমাবদ্ধি নিশ্চিত করে যে generic প্যারামিটার নির্দিষ্ট পদ্ধতি ও বৈশিষ্ট্য সমর্থন করে।
Associated Type (associatedtype) একটি প্রোটোকলের ভিতরে একটি টাইপের জন্য একটি প্লেসহোল্ডার। প্রোটোকল একটি নির্দিষ্ট টাইপ নির্দিষ্ট করে না বরং একটি associatedtype ঘোষণা করে, যা বাস্তবায়নে নির্দিষ্ট হয়: Array এর Element, Dictionary এর Key ও Value।
Swift generic কোডকে প্রতিটি নির্দিষ্ট টাইপের জন্য বিশেষায়ন সংস্করণ এ কম্পাইল করে। ব্যবহারিকভাবে, Int এর জন্য একটি generic ফাংশন Int এর জন্য হাতে লেখা ফাংশনের চেয়ে ধীরে নয়। অমূর্ততার কোনো ওভারহেড নেই।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন