有没有可能有一个通用的buildList函数来处理所有类型的元素?

let filter = Filter(name: "John")
let conditions = buildList<(User) -> Bool> {
  if let name = filter.name {
    { $0.name == name }
  }
  if let maxAge = filter.maxAge {
    { $0.age <= maxAge }
  }
}
let filtered = users.filter { user in
  conditions.allSatisfy { $0(user) }
}

推荐答案

我不会使用结果构建器,而是只需编写如下函数:

func buildArray<T>(_ type: T.Type = T.self, block: (inout [T]) -> Void) -> [T] {
    var array = [T]()
    block(&array)
    return array
}

用途:

let array = buildArray(Int.self) {
    $0.append(1)
    $0.append(2)
    $0.append(3)
    // you can put whatever control flow statements you need in here...
}

如果你真的讨厌一直写$0.append,你可以使用结果构建器:

@resultBuilder
struct ArrayBuilder<T> {
    typealias Component = [T]

    static func buildExpression(_ expression: T) -> Component {
        [expression]
    }

    static func buildBlock(_ components: Component...) -> Component {
        components.flatMap { $0 }
    }

    static func buildArray(_ components: [Component]) -> Component {
        components.flatMap { $0 }
    }

    static func buildOptional(_ component: Component?) -> Component {
        component ?? []
    }

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

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

请注意,这会将闭包中的所有表达式转换为单元素array.然后将它们连接在一起.我没有对此进行基准测试,但我怀疑这会导致相当多的数组分配.如果这是一个问题,您可以try 另一个实现:

@resultBuilder
struct ArrayBuilder<T> {
    enum Component {
        case array([T]), element(T), nothing
    }
    
    static func buildExpression(_ expression: T) -> Component {
        .element(expression)
    }
    
    static func buildBlock(_ components: Component...) -> Component {
        buildArray(components)
    }
    
    static func buildArray(_ components: [Component]) -> Component {
        var array = [T]()
        for component in components {
            switch component {
            case .array(let a): array.append(contentsOf: a)
            case .element(let t): array.append(t)
            default: break
            }
        }
        return .array(array)
    }
    
    static func buildOptional(_ component: Component?) -> Component {
        component ?? .nothing
    }
    
    static func buildEither(first component: Component) -> Component {
        component
    }
    
    static func buildEither(second component: Component) -> Component {
        component
    }
    
    static func buildFinalResult(_ component: Component) -> [T] {
        switch component {
        case .array(let a): return a
        case .element(let t): return [t]
        default: return []
        }
    }
}

这对Component类型使用了枚举,因此闭包中的表达式可以改为.element(expr),从而避免了一些数组分配.

然后,buildArray函数可以如下所示:

func buildArray<T>(_ type: T.Type = T.self, @ArrayBuilder<T> block: () -> [T]) -> [T] {
    block()
}

与前buildArray个不同,SWIFT通常能够根据构建器中的表达式推断数组的类型:

let array = buildArray {
    1
    2
    3
    // you can use if, switch, and for statements in here
}

Swift相关问答推荐

Form中的Divider在macOS上并不完全扩展

在SwiftUI中使用自定义图像填充列表行的正确方法

相互取消任务

物理主体未与 spritekit Swift 的网格图案上的纹理图像对齐

为什么 XUIView 中的 Binding 看不到更新后的值?

使用异步收集发布者值

在 struct 中的序列和非序列泛型函数之间进行 Select

String(validatingUTF8:) 和 String(utf8String:) 之间有区别吗?

如何打印出此 struct 中的数据?

如何在 SWIFTUI 中旋转修剪?

状态变量更改后,SwiftUI 视图不会更改

如何在 Swift 中使用子定义覆盖父类扩展

如何获得不同的插入和移除过渡动画?

在视图中设置所有变量

NSFontAttributeName 已更改为 String

不支持用作符合协议 AnyObject 的具体类型

如何在 SwiftUI 中为删除和禁用配置 ContextMenu 按钮?

<<错误类型>> 奇怪的错误

WKWebView 确实从本地文档文件夹加载资源

显示 UIAlertController 的简单 App Delegate 方法(在 Swift 中)