Result Builder — що це, синтаксис і застосування

Автор: IT Sectr Опубліковано: 2026-06-20 Час читання: 8 хв

Result Builder — атрибут Swift, що реалізується через протокол @resultBuilder, який трансформує послідовність виразів у складове значення. Компілятор перетворює блоки коду з керуючими конструкціями if, for, switch у виклики статичних методів білдера — buildBlock, buildEither, buildArray. Згідно з Swift Evolution proposal SE-0289 (2022), result builders дозволяють створювати декларативні DSL всередині Swift без зовнішніх парсерів. Найвідоміший приклад — @ViewBuilder у SwiftUI, де тіло view будується з умовних і циклічних елементів у декларативному стилі.

Головне

  • Result Builder — атрибут Swift, що перетворює послідовність виразів у результуюче значення через статичні методи білдера
  • @ViewBuilder — найвідоміший приклад: він трансформує кілька view в одне складове представлення TupleView
  • Керуючі конструкції — білдер підтримує if/else, switch, for-in через методи buildOptional, buildEither, buildArray
  • Кастомні білдери можна створювати для своїх DSL — HTML, CSS, конфігурації, запитів
  • Swift 5.4 розширив підтримку result builders на функції та параметри функцій — тепер білдер можна застосувати до аргументу closure

Що таке Result Builder?

Result Builder (раніше відомий як function builders) — це механізм Swift, який дозволяє перетворювати послідовність виразів, розділених переносом рядка, на єдине значення. Він оголошується за допомогою атрибута @resultBuilder, застосованого до структури, яка реалізує статичні методи перетворення.

До появи result builders декларативний синтаксис SwiftUI body був неможливий. Замість компактного списку view розробнику довелося б писати виклики TupleView вручну. Result Builder автоматично обгортає кожен вираз, підтримує розгалуження та цикли, приховуючи складність композиції від розробника.

Згідно з Swift Evolution SE-0289, прийнятим у 2022 році, result builder — це розвиток ідеї function builders (SE-0258, Swift 5.1). Основні зміни: перейменування з @_functionBuilder на @resultBuilder і розширення на параметри функцій, що дозволило використовувати білдери для будь-яких closure-аргументів, а не тільки для body view.

Використовуйте result builders, коли потрібно надати користувачам вашої бібліотеки декларативний синтаксис для побудови складних структур — конфігурацій, запитів, UI-компонентів — без написання імперативного коду збірки.

Як працює 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Об'єднує послідовність виразівДля кожного блоку без розгалужень
buildOptionalОбробляє if без elseЗа наявності if без else
buildEither(first:)Перша гілка if-elseПри if з else
buildEither(second:)Друга гілка if-elseПри if з else
buildArrayОбробляє цикл for-inЗа наявності for-in
buildExpressionПеретворює окремий виразДля кожного виразу перед передачею в buildBlock
buildFinalResultФінальне перетворенняПеред поверненням із closure

Мінімальна реалізація вимагає тільки buildBlock з variadic параметрами — цього достатньо для блоків без розгалужень. Додавання buildOptional та buildEither включає підтримку умовних конструкцій, а buildArray — циклів. Згідно з документацією Swift (2025), рекомендується реалізовувати всі методи для максимальної гнучкості DSL.

buildExpression дозволяє приймати вирази різних типів і перетворювати їх до єдиного типу білдера. Наприклад, у @ViewBuilder buildExpression приймає Text, Image, Button і приводить їх до спільного типу View.

Створення кастомного Result Builder

Розглянемо створення білдера для побудови HTML-рядків. Цей DSL дозволить писати декларативний HTML прямо в Swift:

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>

Згідно зі статтею «Building Custom Result Builders in Swift» від Swift.org (2025), кастомні білдери застосовуються в бібліотеках для побудови конфігураційних файлів, UI-компонентів, маппінгу даних і навіть запитів до бази даних — усюди, де потрібен декларативний синтаксис із підтримкою розгалужень.

@ViewBuilder у SwiftUI

@ViewBuilder — це result builder, вбудований у SwiftUI, який застосовується до параметра content більшості контейнерних view: VStack, HStack, ZStack, Group, List і самої властивості body. Він дозволяє писати кілька view на окремих рядках без ком і обгорток.

@ViewBuilder реалізує всі методи result builder, включаючи підтримку if-else, switch та for-in. Коли умова виконується, buildEither(first:) повертає одну view; коли ні — 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 визначає перевантаження buildBlock для 2–10 виразів. Якщо в блоці більше 10 виразів, компілятор видасть помилку. Рішення — групування через Group або VStack для розбиття на підблоки.

Друге обмеження — відсутність підтримки змінних і присвоєнь всередині білдер-блоку. Не можна оголосити let x = 5 всередині @ViewBuilder. Усі вирази мають бути виразами, що повертають значення типу білдера. Для проміжних обчислень використовуйте обчислення поза білдером або buildExpression з підтримкою різних типів.

Третє обмеження — складність налагодження. Помилки компіляції всередині result builder часто дають заплутані повідомлення, особливо при невідповідності типів у гілках if/else. Використовуйте явні типи, що повертаються, і AnyView для налагодження, хоча останній знижує продуктивність. Згідно з Hacking with Swift (2025), практична порада — починати з простого білдера без розгалужень і додавати підтримку умовних конструкцій поступово.

Часті запитання

Що таке Result Builder у Swift?

Result Builder — атрибут Swift, що перетворює послідовність виразів у результуюче значення через статичні методи. Дозволяє створювати декларативні DSL, найвідоміший приклад — @ViewBuilder у SwiftUI для побудови ієрархії view без імперативного коду.

Як створити свій Result Builder?

Оголосіть структуру з атрибутом @resultBuilder і реалізуйте метод buildBlock мінімум. Для підтримки умов додайте buildOptional і buildEither, для циклів — buildArray. Використовуйте атрибут білдера перед параметром closure у функції.

Які методи обов'язкові для Result Builder?

Обов'язковий тільки buildBlock. Всі інші методи — buildOptional, buildEither, buildArray, buildExpression, buildFinalResult — опціональні та додають підтримку відповідних конструкцій. Чим більше методів реалізовано, тим гнучкіший DSL.

Чому @ViewBuilder — це Result Builder?

@ViewBuilder — це конкретна реалізація result builder для протоколу View. Він визначений у SwiftUI як структура з атрибутом @resultBuilder, що надає методи buildBlock для різних кількостей view (TupleView), buildEither для ConditionalContent і buildArray для ForEach.

Чи є обмеження на кількість виразів у білдері?

Так, стандартні перевантаження buildBlock підтримують до 10 виразів. При перевищенні використовуйте вкладені контейнери (Group, VStack) для розбиття на підблоки. Кастомний білдер може визначити variadic buildBlock без обмеження.

Підсумки

  • Result Builder — атрибут Swift, що трансформує послідовність виразів у єдине значення через статичні методи білдера
  • Компілятор замінює блок коду на виклики buildBlock, buildEither, buildOptional, buildArray залежно від керуючих конструкцій
  • @ViewBuilder — вбудований result builder SwiftUI, що дозволяє писати декларативний код ієрархії view з підтримкою умов і циклів
  • Кастомні білдери застосовуються для побудови DSL: HTML, конфігурацій, запитів — будь-якої структури, що виграє від декларативного синтаксису
  • Обмеження: макс 10 виразів у buildBlock, не можна оголошувати змінні, заплутані помилки компіляції при невідповідності типів
  • Swift 5.4+ — білдери можна застосовувати до параметрів функцій, що розширює сценарії використання за межі body view

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також