Menu
Coddy logo textTech

אתחולים שעלולים להיכשל

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Swift של Coddy. שיעור 20 מתוך 57.

אי אפשר ליצור ערכים מסוימים מכל קלט. אתחול שניתן לכישלון, שנכתב init?, מחזיר nil במקום מופע כשהקלט אינו תקין, כך שאף מופע לא תקין לא יוכל להתקיים:

struct Percentage {
    let value: Int

    init?(_ value: Int) {
        guard value >= 0, value <= 100 else { return nil }
        self.value = value
    }
}

print(Percentage(42)?.value ?? -1)
print(Percentage(150)?.value ?? -1)

פלט:

42
-1

התוצאה של אתחול שניתן להיכשל בו היא אופציונלית, ולכן הקוד הקורא חייב לחלץ ממנה את הערך, בדרך כלל באמצעות if let או guard let:

struct Email {
    let address: String

    init?(_ text: String) {
        let parts = text.split(separator: "@")
        guard parts.count == 2, parts[1].contains(".") else { return nil }
        address = text.lowercased()
    }
}

for text in ["Ada@Mail.com", "not-an-email"] {
    if let email = Email(text) {
        print("valid: \(email.address)")
    } else {
        print("invalid: \(text)")
    }
}

פלט:

valid: ada@mail.com
invalid: not-an-email

הטיפוסים המובנים של Swift משתמשים באותו רעיון: Int("42") ו-Double("x") הם אתחולים שעלולים להיכשל, וכך גם init(rawValue:) של enum. אתחול שעלול להיכשל יכול לקרוא להם ולהעביר הלאה את הכישלון:

struct Coordinate {
    let lat: Double
    let lon: Double

    init?(text: String) {
        let parts = text.split(separator: ",")
        guard parts.count == 2,
              let lat = Double(parts[0]), let lon = Double(parts[1]),
              abs(lat) <= 90, abs(lon) <= 180 else { return nil }
        self.lat = lat
        self.lon = lon
    }
}

print(Coordinate(text: "51.5,-0.1") != nil)
print(Coordinate(text: "95,10") != nil)

פלט:

true
false

השתמשו ב־init? כשערך חסר מספיק כמידע. השתמשו במאתחל שזורק שגיאה, init(...) throws, כשהקורא אמור לדעת איזה כלל נכשל:

struct Username {
    let text: String
    init(_ text: String) throws {
        guard text.count >= 3 else { throw NameError.tooShort }
        guard text.allSatisfy({ $0.isLetter }) else { throw NameError.badCharacters }
        self.text = text
    }
}
challenge icon

אתגר

קל

השלימו את המבנה Rgb, ששומר צבע בתור red, green ו-blue בטווח שבין 0 ל-255. המאתחל הכושל שלו init?(hex:) קורא טקסט כמו #FF8000: הוא מחזיר nil אלא אם הטקסט הוא # ואחריו בדיוק שש ספרות הקסדצימליות. השתמשו ב-Int(text, radix: 16) עבור כל זוג. הוסיפו את label המחושב, שמחזיר rgb(255, 128, 0).

הקוד שסופק קורא צבע אחד בכל שורה ומדפיס את התווית או את invalid: text.

כתבו את הקוד שלכם ב-Rgb.swift. הקובץ main.swift מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.

נסו בעצמכם

// קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    if let color = Rgb(hex: line) {
        print(color.label)
    } else {
        print("invalid: \(line)")
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: Swift אונליין