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

تمرير الأخطاء

جزء من قسم المنطق والتدفق في رحلة Swift على Coddy — الدرس 47 من 56.

يمكن للدالة التي ترمي أخطاء استدعاء دوال أخرى ترمي أخطاء. ينتقل الخطأ تلقائياً إلى أقرب do/catch، دون الحاجة إلى إعادة رمي يدوية.

enum AuthError: Error { case badUser, badPass }

func loadUser(_ name: String) throws -> String {
    if name.isEmpty { throw AuthError.badUser }
    return name
}

func login(_ name: String, _ pass: String) throws -> String {
    let u = try loadUser(name)            // يمرر الخطأ
    if pass.count < 4 { throw AuthError.badPass }
    return "hello \(u)"
}

do {
    print(try login("", "abcd"))
} catch AuthError.badUser {
    print("missing user")
} catch AuthError.badPass {
    print("weak password")
}

اقرأ من الأعلى إلى الأسفل: login يستدعي loadUser باستخدام try. إذا أطلق loadUser خطأً، يتخطى الخطأ جسم login ويستقر عند catch الخارجي. أنت تكتب كل خطوة لتفشل بسرعة وتترك للمستدعي قرار ما يجب فعله.

challenge icon

التحدي

متوسط

قم ببناء سلسلة معالجة (pipeline) صغيرة تتكون من خطوتين قد تثيران أخطاء (throwing steps).

قم بتعريف StepError: Error مع حالتين: negative، و tooBig.

قم بتعريف parseSafe(_ s: String) throws -> Int: تثير .negative عندما يكون العدد الصحيح الذي تم تحليله أقل من 0، وإلا فإنها تعيده. (افترض أن المدخلات يتم تحليلها بنجاح، فقد تعاملت مع ذلك في مكان آخر.)

قم بتعريف capStrict(_ n: Int) throws -> Int: تثير .tooBig عندما يكون n > 100، وإلا فإنها تعيد n.

قم بتعريف processStep(_ s: String) throws -> Int التي تستدعي parseSafe ثم capStrict، مع السماح لأي خطأ بالانتشار (propagate).

اقرأ سطرًا واحدًا من المدخلات: قائمة من النصوص مفصولة بفاصلة. لكل نص، استدعِ processStep داخل بلوك do/catch واطبع سطرًا واحدًا:

  • ok: <n> عند النجاح
  • negative عندما تثير parseSafe خطأً
  • too big عندما تثير capStrict خطأً

للمدخلات 10,-1,200,42، يكون المخرج هو:

ok: 10
negative
too big
ok: 42

ورقة مرجعية

يمكن لـ دالة رامية للأخطاء (throwing function) استدعاء دوال رامية للأخطاء أخرى باستخدام try. تنتقل الأخطاء تلقائيًا إلى أقرب do/catch:

enum AuthError: Error { case badUser, badPass }

func loadUser(_ name: String) throws -> String {
    if name.isEmpty { throw AuthError.badUser }
    return name
}

func login(_ name: String, _ pass: String) throws -> String {
    let u = try loadUser(name)   // ينتقل الخطأ للأعلى إذا تم رميه
    if pass.count < 4 { throw AuthError.badPass }
    return "hello \(u)"
}

do {
    print(try login("", "abcd"))
} catch AuthError.badUser {
    print("missing user")
} catch AuthError.badPass {
    print("weak password")
}

إذا قامت loadUser برمي خطأ، يتخطى التنفيذ بقية login وينتقل مباشرة إلى catch الخارجية. لا حاجة لإعادة رمي الخطأ يدويًا.

جرّب بنفسك

let parts = readLine()!.components(separatedBy: ",")

// للقيام به: enum StepError; parseSafe; capStrict; processStep;
// لكل جزء، قم بـ do/try لـ processStep، والتقط (catch) كل فرع، ثم اطبع
quiz iconاختبر نفسك

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

جميع دروس المنطق والتدفق