DSL in Swift: 如何在一晚内创建自己的编程语言

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:当通用性成为敌人

\n\n

设想你正在为网络配置、日志解析或业务规则描述编写代码。每次都要面对重复的结构、大量的括号、嵌套的条件语句,以及他人代码的痛苦阅读。感觉很熟悉吧?

\n\n

在这种情况下,领域特定语言(DSL) 就能派上用场。这不是魔法,也不是重新发明轮子——而是一种让代码可读性达到自我文档化程度的方法。在本文中,我们将详细讲解如何在 Swift 中创建你自己的 DSL——强大、优雅,且无需编译器。

\n\n

Swift 中的 DSL 不仅是一种时髦的 iOS 开发潮流。它是一种用于 SwiftUI、Combine,甚至后端库中的工具。你将学习设计能够解决特定任务的语言:从数据解析到 UI 描述。让我们开始吧!

\n\n

什么是 DSL?为什么开发者需要它?

\n\n

领域特定语言 是一种针对单一狭窄领域量身定制的语言。与通用语言(如 Swift 或 Python)不同,DSL 使用你所在领域术语的语言。例如,与其写:

\n\n
let config = NetworkConfig()\nconfig.host = "api.example.com"\nconfig.port = 443\nconfig.timeout = 30
\n\n

不如写:

\n\n
let config = networkConfig {\n    host("api.example.com")\n    port(443)\n    timeout(30)\n}
\n\n

第二种写法读起来像是人类语言的指令。这就是 DSL 的目标——减少认知负荷,让代码实现自我文档化。

\n\n

在 Swift 中,创建 DSL 最常使用:

\n
    \n
  • Result Builders——Swift 5.4+ 的新特性,允许使用声明式语法构建嵌套结构。
  • \n
  • 函数式链——经典的构建器模式。
  • \n
  • 运算符——运算符重载以创建流畅接口。
  • \n
\n\n

但让我们直接进入正题。我们将创建一个用于解析 CSV 文件的 DSL——这是一项每个开发者一生中至少会遇到一次的任务。

\n\n

示例 1:一个简单的网络配置 DSL

\n\n

让我们从一个演示机制的基本示例开始。假设我们需要描述 HTTP 请求。与其使用一堆参数,不如使用一个简洁的 DSL。

\n\n
// Define the request structure\nstruct HTTPRequest {\n    var method: String = "GET"\n    var path: String = "/"\n    var headers: [String: String] = [:]\n    var body: Data? = nil\n}\n\n// Create a DSL using Result Builder\n@resultBuilder\nstruct RequestBuilder {\n    static func buildBlock(_ components: HTTPRequestModifier...) -> HTTPRequest {\n        var request = HTTPRequest()\n        for mod in components {\n            mod.apply(&request)\n        }\n        return request\n    }\n}\n\n// Request modifiers\nprotocol HTTPRequestModifier {\n    func apply(_ request: inout HTTPRequest)\n}\n\nstruct MethodModifier: HTTPRequestModifier {\n    let method: String\n    func apply(_ request: inout HTTPRequest) {\n        request.method = method\n    }\n}\n\nstruct PathModifier: HTTPRequestModifier {\n    let path: String\n    func apply(_ request: inout HTTPRequest) {\n        request.path = path\n    }\n}\n\n// Helper functions\nfunc method(_ m: String) -> HTTPRequestModifier { MethodModifier(method: m) }\nfunc path(_ p: String) -> HTTPRequestModifier { PathModifier(path: p) }\n\n// Usage\n@RequestBuilder\nfunc buildGetRequest() -> HTTPRequest {\n    method("GET")\n    path("/users")\n}\n\nlet request = buildGetRequest()\nprint(request.method, request.path) // GET /users
\n\n

这段代码是 Swift 中任何 DSL 的基础。@resultBuilder 收集块内的所有表达式,并将它们转换为单一结构。重要提示:每个元素都是一个修改状态的操作器。

\n\n

现在让我们将任务复杂化:添加嵌套和条件。

博客

书籍推荐