@_ functionBuilder少于2个项目时出现初始化器问题

问题描述 投票:0回答:1

我正在尝试使用Swift 5.1 @_functionBuilder设置小型DSL,这是我的问题,假设我有一个Section类型,其中包含多行,我希望以在SwiftUI中构建堆栈的方式来构建它们。这是我的类型:

struct Section {
    var rows : [Row]

    struct Row {
        let label : String
    }
}

这是我的函数生成器,它需要几行并将它们分成一个部分:

@_functionBuilder
struct SectionBuilder {
    static func buildBlock(_ segments: Section.Row...) -> Section {
        Section(rows: segments)
    }
}

以及我的Section类型的扩展名,以使用函数构建器构建一个部分:

extension Section {
    init(@SectionBuilder _ content: () -> Section) {
        self = content()
    }
}

这样,我可以构建类似于DSL的部分:

let section2 = Section {
    Section.Row(label: "first")
    Section.Row(label: "second")
}

而且它工作得很好,除非我只想排一行或什么都不排:

let section1 = Section {
    Section.Row(label: "alone") // Cannot convert value of type 'Section.Row' to closure result type 'Section'
}

let section0 = Section { } // Cannot convert value of type '() -> ()' to expected argument type '() -> Section'

但是最奇怪的是,当我不使用初始化程序执行完全相同的操作时,它可以完美地工作:

@SectionBuilder
func getSection0() -> Section {
}

@SectionBuilder
func getSection1() -> Section {
    Section.Row(label: "alone")
}

@SectionBuilder
func getSection2() -> Section {
    Section.Row(label: "first")
    Section.Row(label: "second")
}

所以,如果有人可以解释我做错了什么,我全是耳!提前致谢。

EDIT:我也尝试过在SectionBuilder中添加这两种方法,但这无济于事...

static func buildBlock(_ segment: Section.Row) -> Section {
    Section(rows: [segment])
}

static func buildBlock() -> Section {
    Section(rows: [])
}
swift dsl swift5.1 function-builder
1个回答
0
投票

我找到了部分但有用的答案!

对于单行部分,我只需要添加此初始化程序:

extension Section {
    init(@SectionBuilder _ content: () -> Row) {
        self.init(rows: [content()])
    }
}

不幸的是,当我没有与此行的行时,它不起作用:

extension Section {
    init(@SectionBuilder _ content: () -> Void) {
        self.init(rows: [])
    }
}

let section0 = Section { } // Cannot invoke initializer for type 'Section' with an argument list of type '(@escaping () -> ())'

所以我尝试使用转义的闭包:

extension Section {
    init(@SectionBuilder _ content: @escaping () -> Void) {
        self.init(rows: [])
    }
}

let section0 = Section { } // Expression type 'Section' is ambiguous without more context

因此,由于我仅使用语法糖,所以可以使用这种DSL表示法:

extension Section {
    init() {
        self.init(rows: [])
    }
}

let section0 = Section()
© www.soinside.com 2019 - 2024. All rights reserved.