Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

امتدادات البروتوكولات

جزء من قسم البرمجة كائنية التوجه في رحلة Swift على Coddy. الدرس 29 من 57.

يوفّر امتداد البروتوكول تطبيقًا افتراضيًا لأساليب البروتوكول. ويحصل عليه كل نوع متوافق مجانًا، ولا يزال بإمكان النوع توفير نسخته الخاصة:

protocol Greeter {
    var name: String { get }
    func greet() -> String
}

extension Greeter {
    func greet() -> String { "Hello, \(name)!" }
}

struct English: Greeter { let name: String }
struct Pirate: Greeter {
    let name: String
    func greet() -> String { "Ahoy, \(name)!" }
}

print(English(name: "Ada").greet())
print(Pirate(name: "Ada").greet())

الناتج:

Hello, Ada!
Ahoy, Ada!

يمكن للامتداد أيضًا إضافة أساليب جديدة مبنية بالكامل على المتطلبات. يكتب النوع المطابق الجزء الصغير المطلوب ويحصل على الباقي:

protocol Scored {
    var points: [Int] { get }
}

extension Scored {
    var total: Int { points.reduce(0, +) }
    var best: Int { points.max() ?? 0 }
    func summary() -> String { "total \(total), best \(best)" }
}

struct Player: Scored {
    let points: [Int]
}

print(Player(points: [3, 9, 4]).summary())

الناتج:

total 16, best 9

يتيح هذا مشاركة السلوك بين الهياكل والفئات والتعدادات دون استخدام الوراثة. تعمل المكتبة القياسية بالطريقة نفسها: تحصل كل Collection على isEmpty وfirst وmap من امتدادات البروتوكول.

extension Collection {
    // isEmpty, first, map, filter, ... كلها معرّفة مرة واحدة هنا
    // وكل array و set و dictionary و string يحصل عليها
}

يضيف الامتداد المقيّد أساليبَ لبعض الأنواع المتوافقة فقط، ويُكتب باستخدام where:

protocol Container {
    associatedtype Item
    var items: [Item] { get }
}

extension Container where Item == Int {
    var sum: Int { items.reduce(0, +) }
}

struct Box: Container {
    var items: [Int]
}

print(Box(items: [2, 5]).sum)

الناتج:

7
challenge icon

التحدي

سهل

أعلن عن بروتوكول Priced يتطلب var price: Int { get } (بالسنتات) وvar formatted: String { get }. في امتداد البروتوكول، امنح formatted قيمة افتراضية تُرجع $4.50، وأضف طريقة isAffordable(budget:) تُرجع ما إذا كان السعر يناسب الميزانية. اجعل البنيتين Coffee (بسعر 450) وSandwich (مع price مخزّن) متوافقتين مع البروتوكول. يجب أن تستبدل Coffee القيمة الافتراضية لـ formatted بـ coffee $4.50.

يقرأ الكود المتوفر ميزانية، ثم أسطرًا تحتوي على coffee أو sandwich,650. ويطبع formatted وyes أو no لكل عنصر.

ضع كودك في Priced.swift وCoffee.swift وSandwich.swift. يحتوي main.swift على كود الإدخال/الإخراج المتوفر، ولا يمكن تعديله.

جرّب بنفسك

// كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
var input: [String] = []
while let line = readLine() { input.append(line) }
let budget = Int(input[0])!
for line in input.dropFirst() {
    let item: any Priced = line == "coffee" ? Coffee() : Sandwich(price: Int(line.split(separator: ",")[1])!)
    print("\(item.formatted) \(item.isAffordable(budget: budget) ? "yes" : "no")")
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: Playground لـ Swift