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"
}
// Compiler transforms this into:
// StringBuilder.buildBlock("Hello", "World", "from", "Swift")
// Result: "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 Documentation (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("Footer")
    }
}
// Result: <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("Profile")
                .font(.title)

            if isLoggedIn {
                Text("Welcome back!")
                    .foregroundColor(.green)
            } else {
                Button("Log In") { }
            }
        }
    }
}

Без @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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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