← Swift言語ページに戻る
🐦

Swift言語のサンプルコード

文法解説で学んだ内容を組み合わせた、難易度が段階的に上がる3本の実践的なサンプルプログラムを紹介します。

サンプル1:struct と protocol で図形の面積を計算する

protocolで「面積を持つ図形」という共通のふるまいを定義し、CircleRectangleという異なるstructがそれぞれ準拠します。呼び出す側は具体的な型を意識せず、Shapeプロトコル越しに統一的に扱えます(ポリモーフィズム)。structは値型なので、配列にコピーされて格納されても意図しない副作用が起きません。

SAMPLE PROGRAM
protocol Shape {
    var name: String { get }
    var area: Double { get }
}

struct Circle: Shape {
    let radius: Double
    var name: String { "円" }
    var area: Double { Double.pi * radius * radius }
}

struct Rectangle: Shape {
    let width: Double
    let height: Double
    var name: String { "長方形" }
    var area: Double { width * height }
}

func printReport(_ shapes: [Shape]) {
    var total = 0.0
    for shape in shapes {
        let areaText = String(format: "%.2f", shape.area)
        print("\(shape.name): 面積 \(areaText)")
        total += shape.area
    }
    let totalText = String(format: "%.2f", total)
    print("合計面積: \(totalText)")
}

let shapes: [Shape] = [
    Circle(radius: 3),
    Rectangle(width: 4, height: 5)
]
printReport(shapes)
// 円: 面積 28.27
// 長方形: 面積 20.00
// 合計面積: 48.27

サンプル2:スタックを使った括弧チェックと二分探索

1つ目はスタック(後入れ先出し)を使い、文字列内の括弧の対応が正しいかを判定するプログラムです。開き括弧が来たらスタックに積み、閉じ括弧が来たら直前に積んだ開き括弧と対応するか確認します。2つ目はソート済み配列に対する二分探索で、計算量はO(log n)です(文法解説の14番を参照)。

SAMPLE PROGRAM
// 1) 括弧の対応をスタックでチェックする
func isValidParentheses(_ text: String) -> Bool {
    var stack: [Character] = []
    let pairs: [Character: Character] = [")": "(", "]": "[", "}": "{"]

    for char in text {
        if char == "(" || char == "[" || char == "{" {
            stack.append(char)          // 開き括弧を積む
        } else if let open = pairs[char] {
            if stack.popLast() != open { // 対応しない、または空なら不正
                return false
            }
        }
    }
    return stack.isEmpty  // 最後に閉じ残しがなければ正しい
}

print(isValidParentheses("{[()()]}"))  // true
print(isValidParentheses("{[(])}"))    // false

// 2) 二分探索:O(log n)
func binarySearch(_ array: [Int], target: Int) -> Int? {
    var low = 0
    var high = array.count - 1

    while low <= high {
        let mid = (low + high) / 2
        if array[mid] == target {
            return mid
        } else if array[mid] < target {
            low = mid + 1
        } else {
            high = mid - 1
        }
    }
    return nil
}

let sortedNumbers = [1, 3, 5, 7, 9, 11, 13]
if let index = binarySearch(sortedNumbers, target: 9) {
    print("9はインデックス\(index)で見つかりました")
}

サンプル3:Optional型とエラーハンドリングによる入力バリデーション

フォーム入力のように「値が空かもしれない/形式が不正かもしれない」状況を、Optional型・guard let・独自のErrorenum・do/try/catchResult型を組み合わせて安全に処理する例です。エラーの種類ごとにassociated valueで詳細情報を持たせ、呼び出し側で個別にハンドリングしています。

SAMPLE PROGRAM
enum ValidationError: Error {
    case empty
    case invalidFormat
    case tooYoung(age: Int)
}

struct UserInput {
    let nameText: String?
    let ageText: String?
}

func validate(_ input: UserInput) throws -> (name: String, age: Int) {
    guard let nameText = input.nameText, !nameText.isEmpty else {
        throw ValidationError.empty
    }
    guard let ageText = input.ageText, let age = Int(ageText) else {
        throw ValidationError.invalidFormat
    }
    guard age >= 18 else {
        throw ValidationError.tooYoung(age: age)
    }
    return (nameText, age)
}

func register(_ input: UserInput) {
    do {
        let result = try validate(input)
        print("登録OK: \(result.name)さん(\(result.age)歳)")
    } catch ValidationError.empty {
        print("名前が空です")
    } catch ValidationError.invalidFormat {
        print("年齢の形式が不正です")
    } catch ValidationError.tooYoung(let age) {
        print("18歳未満のため登録できません(\(age)歳)")
    } catch {
        print("不明なエラー: \(error)")
    }
}

register(UserInput(nameText: "花子", ageText: "17"))
register(UserInput(nameText: "太郎", ageText: "20"))

// Result型で成功/失敗を表現する例
func divide(_ a: Int, _ b: Int) -> Result<Int, ValidationError> {
    guard b != 0 else { return .failure(.invalidFormat) }
    return .success(a / b)
}

switch divide(10, 0) {
case .success(let value):
    print("計算結果: \(value)")
case .failure(let error):
    print("エラー: \(error)")
}

理解度チェッククイズに挑戦する →