Result Builder — その概要、構文、応用

著者: IT Sectr 公開日: 2026-06-20 読了時間: 8 分

Result Builder は、プロトコル @resultBuilder を介して実装されるSwiftの属性であり、一連の式を複合値に変換します。コンパイラは、制御構文 ifforswitch を含むコードブロックを、ビルダーの静的メソッド — buildBlockbuildEitherbuildArray — の呼び出しに変換します。Swift Evolution提案SE-0289(2022)によると、result buildersを使用すると、外部パーサーなしでSwift内に宣言的DSLを作成できます。最も有名な例はSwiftUIの @ViewBuilder で、ビューのボディが条件付き要素と反復要素から宣言的スタイルで構築されます。

重要ポイント

  • Result Builder — ビルダーの静的メソッドを介して一連の式を結果値に変換するSwift属性
  • @ViewBuilder — 最も有名な例:複数のビューを単一の複合表現 TupleView に変換します
  • 制御構文 — ビルダーは if/elseswitchfor-in をメソッド buildOptionalbuildEitherbuildArray を介してサポートします
  • カスタムビルダー は独自のDSL(HTML、CSS、設定、クエリ)用に作成できます
  • Swift 5.4 はresult buildersのサポートを関数と関数パラメータに拡張しました — これでクロージャ引数にビルダーを適用できます

Result Builderとは?

Result Builder(以前はfunction buildersとして知られていました)は、改行で区切られた一連の式を単一の値に変換するSwiftのメカニズムです。これは、静的変換メソッドを実装する構造体に適用される @resultBuilder 属性を使用して宣言されます。

Result builders以前は、SwiftUI bodyの宣言的構文は不可能でした。ビューのコンパクトなリストの代わりに、開発者は手動で TupleView 呼び出しを書く必要がありました。Result Builderは自動的に各式をラップし、分岐とループをサポートし、開発者から構成の複雑さを隠します。

2022年に承認されたSwift Evolution SE-0289によると、result builderはfunction builders(SE-0258、Swift 5.1)のアイデアの進化形です。主な変更点:@_functionBuilder から @resultBuilder への名称変更と、関数パラメータへの拡張により、ビューボディだけでなく任意のクロージャ引数にビルダーを使用できるようになりました。

ライブラリのユーザーに複雑な構造(設定、クエリ、UIコンポーネント)を構築するための宣言的構文を提供する必要がある場合、Result buildersを使用してください。命令的なアセンブリコードを書く必要はありません。

Result Builderの仕組み

Swiftコンパイラは、@resultBuilder でマークされた各コードブロックを、ビルダーの静的メソッドの呼び出しシーケンスに変換します。文字列を連結するシンプルなビルダーを見てみましょう:

swift
@resultBuilder
struct StringBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: " ")
    }
}

このビルダーの使用 — 各文字列が個別の行でスペースで連結されます:

swift
@StringBuilder
func greeting() -> String {
    "Hello"
    "World"
    "from"
    "Swift"
}
// コンパイラはこれを変換します:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// 結果: "Hello World from Swift"

コンパイラは連続する式をグループ化し、可変長パラメータとして buildBlock に渡します。式の間に if が現れると、コンパイラは分岐のために buildOptional または buildEither を呼び出します。for-in ループの場合は buildArray を呼び出します。このように、通常のSwiftコードは最終値を構築する呼び出しチェーンに変換されます。

ビルダーのメソッド:buildBlock、buildOptional、buildEither

各result builderは、コンパイラが変換中に呼び出す静的メソッドのセットを定義します。主要なメソッド:

メソッド目的呼び出されるタイミング
buildBlock一連の式を結合します分岐のない各ブロックに対して
buildOptionalelseなしのifを処理しますifelse なしで存在する場合
buildEither(first:)if-elseの最初の分岐ifelse の場合
buildEither(second:)if-elseの2番目の分岐ifelse の場合
buildArrayfor-inループを処理しますfor-in が存在する場合
buildExpression個々の式を変換します各式をbuildBlockに渡す前
buildFinalResult最終変換クロージャから戻る前

最小限の実装には、可変長パラメータを持つ buildBlock のみが必要です — これは分岐のないブロックに十分です。buildOptionalbuildEither を追加すると条件構文のサポートが含まれ、buildArray を追加するとループのサポートが含まれます。Swiftドキュメント(2025)によると、DSLの最大の柔軟性のためにすべてのメソッドを実装することを推奨します。

buildExpression は異なるタイプの式を受け入れ、それらを単一のビルダータイプに変換できます。例えば、@ViewBuilderでは、buildExpressionTextImageButton を受け入れ、共通の View タイプに変換します。

カスタムResult Builderの作成

HTML文字列を構築するためのビルダー作成を考えてみましょう。このDSLを使用すると、Swift内で直接宣言的にHTMLを記述できます:

swift
@resultBuilder
enum HTMLBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined()
    }

    static func buildOptional(_ component: String?) -> String {
        component ?? ""
    }

    static func buildEither(first component: String) -> String {
        component
    }

    static func buildEither(second component: String) -> String {
        component
    }

    static func buildArray(_ components: [String]) -> String {
        components.joined()
    }
}

カスタムビルダーを使用したHTML生成:

swift
func div(@HTMLBuilder _ content: () -> String) -> String {
    "<div>\(content())</div>"
}

func p(_ text: String) -> String {
    "<p>\(text)</p>"
}

let page = div {
    p("Hello")
    p("World")

    if showFooter {
        p("フッター")
    }
}
// 結果: <div><p>Hello</p><p>World</p><p>Footer</p></div>

Swift.org(2025)の記事「Building Custom Result Builders in Swift」によると、カスタムビルダーは設定ファイル、UIコンポーネント、データマッピング、さらにはデータベースクエリを構築するためのライブラリで使用されています — 分岐サポート付きの宣言的構文が必要なあらゆる場所で。

SwiftUIの@ViewBuilder

@ViewBuilder はSwiftUIに組み込まれたresult builderで、ほとんどのコンテナビューの content パラメータに適用されます:VStackHStackZStackGroupList、および body プロパティ自体。カンマやラッパーなしで複数のビューを個別の行に記述できます。

@ViewBuilderはすべてのresult builderメソッドを実装し、if-elseswitchfor-in のサポートを含みます。条件が真の場合、buildEither(first:)は一方のビューを返し、偽の場合、buildEither(second:)はもう一方のビューを返します。両方の分岐は同じタイプを返す必要がありますが、SwiftUIは内部で AnyView または ConditionalContent によるタイプ消去を使用します。

swift
struct GreetingView: View {
    let isLoggedIn: Bool

    var body: some View {
        VStack {
            Image(systemName: "person.circle")
            Text("プロフィール")
                .font(.title)

            if isLoggedIn {
                Text("おかえりなさい!")
                    .foregroundColor(.green)
            } else {
                Button("ログイン") { }
            }
        }
    }
}

@ViewBuilderがない場合、同じコードには各条件セクションに Group または AnyView の使用が必要となり、パフォーマンスが低下します。@ViewBuilderは各組み合わせに対して最も効率的な表現 — ConditionalContent または TupleView — を自動的に選択します。

Result Builderの制限

最初の制限は、buildBlock内の 式の最大数 です。Swift標準ライブラリは2〜10個の式用のbuildBlockオーバーロードを定義しています。ブロックに10個を超える式がある場合、コンパイラはエラーを生成します。解決策は、GroupまたはVStackを使用してサブブロックに分割することです。

2番目の制限は、ビルダーブロック内での 変数と代入のサポート不足 です。@ViewBuilder内で let x = 5 を宣言できません。すべての式はビルダータイプの値を返す式でなければなりません。中間計算には、ビルダー外での計算または異なるタイプをサポートする buildExpression を使用してください。

3番目の制限は デバッグの複雑さ です。Result builder内のコンパイルエラーは、特に if/else 分岐でタイプが一致しない場合に混乱を招くメッセージを生成することがよくあります。デバッグには明示的な戻り値の型と AnyView を使用してください。ただし、後者はパフォーマンスを低下させます。Hacking with Swift(2025)によると、実用的なアドバイスとして、分岐なしのシンプルなビルダーから始めて、条件構文のサポートを段階的に追加することです。

よくある質問

SwiftのResult Builderとは?

Result Builder は、静的メソッドを介して一連の式を結果値に変換するSwift属性です。宣言的DSLを作成でき、最も有名な例は命令コードなしでビュー階層を構築するためのSwiftUIの@ViewBuilderです。

独自のResult Builderを作成するには?

@resultBuilder 属性を持つ構造体を宣言し、少なくとも buildBlock メソッドを実装します。条件をサポートするには buildOptionalbuildEither を追加し、ループには buildArray を追加します。関数のクロージャパラメータの前にビルダー属性を使用します。

Result Builderに必須のメソッドは?

buildBlock のみが必須です。他のすべてのメソッド — buildOptionalbuildEitherbuildArraybuildExpressionbuildFinalResult — はオプションで、対応する構文のサポートを追加します。実装するメソッドが多いほど、DSLは柔軟になります。

@ViewBuilderがResult Builderなのはなぜ?

@ViewBuilder はViewプロトコル用のresult builderの具体的な実装です。SwiftUIで @resultBuilder 属性を持つ構造体として定義され、異なる数のビュー用のbuildBlockメソッド(TupleView)、ConditionalContent用のbuildEither、ForEach用のbuildArrayを提供します。

ビルダー内の式の数に制限はありますか?

はい、標準のbuildBlockオーバーロードは最大10個の式をサポートします。それを超える場合は、ネストされたコンテナ(Group、VStack)を使用してサブブロックに分割します。カスタムビルダーは制限なしの可変長buildBlockを定義できます。

まとめ

  • Result Builder — ビルダーの静的メソッドを介して一連の式を単一の値に変換するSwift属性
  • コンパイラ は制御構文に応じてコードブロックを buildBlockbuildEitherbuildOptionalbuildArray の呼び出しに置き換えます
  • @ViewBuilder — 条件とループをサポートする宣言的ビュー階層コードを記述できるSwiftUIの組み込みresult builder
  • カスタムビルダー はDSL(HTML、設定、クエリ)の構築に使用されます — 宣言的構文の恩恵を受ける任意の構造
  • 制限:buildBlock内の最大10個の式、変数を宣言できない、タイプ不一致時の混乱するコンパイルエラー
  • Swift 5.4+ — ビルダーを関数パラメータに適用でき、ビューボディを超えたユースケースを拡大

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください