@_functionBuilder 当少于 2 个项目时初始化程序出现问题
@_functionBuilder problem with initializer when there is less than 2 items
我正在尝试使用 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")
}
它工作得很好,除非我只想有一行,或者 none:
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")
}
所以,如果有人能解释我做错了什么,我洗耳恭听!
提前致谢。
编辑:我也尝试在 SectionBuilder
中添加这两种方法,但没有帮助...
static func buildBlock(_ segment: Section.Row) -> Section {
Section(rows: [segment])
}
static func buildBlock() -> Section {
Section(rows: [])
}
我找到了部分但可用的答案!
对于单行部分,我只需要添加这个初始值设定项:
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()
我正在尝试使用 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")
}
它工作得很好,除非我只想有一行,或者 none:
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")
}
所以,如果有人能解释我做错了什么,我洗耳恭听! 提前致谢。
编辑:我也尝试在 SectionBuilder
中添加这两种方法,但没有帮助...
static func buildBlock(_ segment: Section.Row) -> Section {
Section(rows: [segment])
}
static func buildBlock() -> Section {
Section(rows: [])
}
我找到了部分但可用的答案!
对于单行部分,我只需要添加这个初始值设定项:
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()