Swiftの「クロージャ式」と「計算型プロパティ」を最短で理解する

Swift を書いていると 「クロージャ式(closure)」「計算型プロパティ(computed property)」 は見た目が似ていて混乱しがち。この記事では、両者の違いを 一発で腹落ち させる表と、動くサンプルコードで解説します。そのままコピペOK です。


結論サマリ(比較表)


サンプル1:クロージャ式の基本(引数あり/なし、差し替え、値キャプチャ)

import Foundation

struct MathBox {
    // ① 引数ありクロージャ(Int -> Int)
    var transform: (Int) -> Int = { x in x * 2 }

    // ② 引数なしクロージャ(() -> Int)
    var constant: () -> Int = { 5 * 5 }  // 25

    // ③ 値キャプチャ(必要な値だけ取り込む)
    private var factor: Int = 3
    // 初回アクセス時点の factor を閉じ込める(struct なので [unowned self] は使わない)
    lazy var multiply: (Int) -> Int = { [factor] x in
        x * factor
    }
}

// 使い方
var box = MathBox()
print(box.transform(10)) // 20
print(box.constant())    // 25
print(box.multiply(4))   // 12

// 差し替え(再代入できるのが強み)
box.transform = { x in x * 3 }
print(box.transform(10)) // 30

ポイント

  • クロージャは「関数そのもの」を値として保管でき、実装を差し替えられる。
  • struct のプロパティクロージャで self を捕まえる必要があるときは
    lazy を付けて、必要な値だけ [factor] のように値キャプチャするのが安全。
  • multiply初回アクセス時点の factor を固定して使います。
    「いつも最新の factor を使いたい」ならメソッドにします👇
struct MathBox2 {
    private var factor = 3
    mutating func setFactor(_ v: Int) { factor = v }
    func multiply(_ x: Int) -> Int { x * factor }
}

参考:classself をクロージャが参照する場合は循環参照対策として
[unowned self] / [weak self] を使います(struct には不要&不可)。


サンプル2:計算型プロパティの基本(() なし でアクセス)

import Foundation

struct Rectangle {
    var width: Double
    var height: Double

    // 計算型プロパティ(読み取り専用)
    var area: Double {
        width * height
    }

    // 参考:setter を持たせることも可能
    // var area: Double {
    //     get { width * height }
    //     set { width = sqrt(newValue); height = sqrt(newValue) }
    // }
}

let r = Rectangle(width: 4, height: 5)
print(r.area) // 20  ← () を付けないのが「プロパティ」

ポイント

  • 「値として見せたい」時に最適。引数は取らない
  • 毎回 get が評価されるが、呼び出し側からは ただの値 に見える。

よくあるつまずき:呼び方ミス

クロージャをプロパティにした場合

var constant: () -> Int = { 25 }
constant()   // ✅ 正しい(関数呼び出し)
constant     // ❌ 関数オブジェクト自体(呼んでいない)

計算型プロパティの場合

var constant: Int { 25 }
constant     // ✅ 正しい(値)
constant()   // ❌ コンパイルエラー(プロパティに () は不要)

Playground は「未完成の行(末尾に . がぶら下がる等)」があると落ちやすいです。
完成させてから実行しましょう(自動実行→手動実行への切り替えも有効)。


使い分けガイド(実務感)

  • 状態に応じて処理を差し替えたい
    → クロージャ式
    例)戦略パターン・DI、テストでモック関数差し替え、アニメ/フィルタ切り替え
  • “値”として扱いたい、API を読みやすくしたい
    → 計算型プロパティ
    例)user.fullNamerect.areaview.intrinsicContentSize

SwiftUIの実例(肌感覚で覚える)

1) クロージャが自然な場面(イベントハンドラ)

import SwiftUI

struct ClosureExample: View {
    var body: some View {
        Button("Tap me") {
            // ここがクロージャ(() -> Void)
            print("Tapped!")
        }
    }
}

2) 計算型プロパティが自然な場面(表示用の派生値)

import SwiftUI

struct User {
    var firstName: String
    var lastName: String
    var fullName: String { "\(lastName) \(firstName)" }  // 値として見せたい
}

struct PropertyExample: View {
    let user = User(firstName: "太郎", lastName: "山田")
    var body: some View {
        Text(user.fullName) // () なしで自然に読める
    }
}

もう一歩:パフォーマンスと設計の勘所

  • インライン化の期待
    単純な計算型プロパティは最適化されやすい。高頻度アクセスで軽い算出ならプロパティが読みやすく高速。
  • DI・戦略の切替
    ユースケース層や UI のイベント処理の差し替えは クロージャ が強力。テスト時に処理を注入しやすい。
  • 命名で迷子を防ぐ
    クロージャプロパティには on…, handler, transform, predicate など
    「関数っぽさが伝わる名前」 を付けると呼び方ミスが減る(例:calcProFn())。

まとめ:選択基準は「値として見せたいか」「処理を差し替えたいか」

  • 値として扱いたい(引数不要・読みやすさ重視)→ 計算型プロパティ
  • 処理を差し替えたい / 引数を取りたいクロージャ式

迷ったら「呼び方」で決める:
() を付けたいならクロージャ、付けたくないならプロパティ。


コメント

Copied title and URL