Menu
Coddy logo textTech

失敗する初期化子

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 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:) も同様です。失敗可能なイニシャライザはこれらを呼び出し、失敗をそのまま伝播できます。

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

チャレンジ

簡単

red、green、blueとして0から255までの色を格納する構造体Rgbを完成させてください。失敗可能なイニシャライザinit?(hex:)は#FF8000のようなテキストを読み取ります。このイニシャライザは、テキストが#に続くちょうど6桁の16進数でない限り、nilを返します。各ペアにはInt(text, radix: 16)を使用してください。rgb(255, 128, 0)を返す計算プロパティlabelを追加してください。

提供されたコードは1行につき1色を読み取り、ラベルまたは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プレイグラウンド