Vapor开发中Swift数组元素转结构体变量的可行性问询
嗨,作为Swift新手碰到这种需求确实会有点摸不着头脑,我来帮你拆解怎么实现!
首先得明确一个关键点:Swift是静态类型语言,结构体的属性在编译时就已经固定了,没法在运行时动态添加新属性。而Vapor要求的独立字符串变量,本质上是结构体的静态属性,所以咱们得换个思路——用编译前的代码生成来实现“改数组就自动生成变量”的需求。
方案一:用Sourcery(推荐,Swift生态常用的代码生成工具)
Sourcery可以帮你根据自定义的模板和数据源自动生成Swift代码,完美适配这种场景。步骤如下:
- 安装Sourcery:可以用Homebrew安装
brew install sourcery,或者通过Swift Package Manager集成到项目里。 - 定义你的字段数组:在项目里新建一个文件(比如
Constants.swift),写入:
// Constants.swift import Foundation let formFields = ["thing", "other thing", "third thing"]
- 创建Sourcery模板:在项目根目录新建一个
.stencil文件(比如FormDataTemplate.stencil),内容如下:
// Generated automatically - DO NOT EDIT import Vapor struct FormData: Content { {% for field in formFields %} var {{ field.replacingOccurrences(of: " ", with: "+") }}: String = "" {% endfor %} }
这个模板会遍历formFields数组,把每个元素的空格替换成+,生成对应的空字符串属性,同时让结构体符合Vapor的Content协议。
4. 配置Sourcery自动生成:在项目根目录创建sourcery.yml配置文件,指定模板和生成路径:
sources: - ./Sources/App templates: - ./FormDataTemplate.stencil output: - ./Sources/App/Generated
然后把Sourcery的执行命令添加到Xcode的Build Phases里(Run Script),这样每次编译前都会自动更新生成的代码:
sourcery --config sourcery.yml
之后你只要修改formFields数组,下次编译时Sourcery就会自动更新FormData结构体的属性,完全不用手动写变量!
方案二:用Swift脚本手动生成(无需第三方工具)
如果不想用Sourcery,也可以写一个简单的Swift脚本自己生成代码:
- 编写生成脚本:在项目根目录新建
generateFormData.swift,内容如下:
// generateFormData.swift import Foundation // 这里就是你要维护的数组 let fields = ["thing", "other thing", "third thing"] // 处理每个字段,生成属性代码 let propertyLines = fields.map { field in let varName = field.replacingOccurrences(of: " ", with: "+") return " var \(varName): String = \"\"" }.joined(separator: "\n") // 拼接完整的结构体代码 let structCode = """ // Generated automatically - DO NOT EDIT import Vapor struct FormData: Content { \(propertyLines) } """ // 把代码写入生成文件 let outputPath = "./Sources/App/Models/GeneratedFormData.swift" try structCode.write(toFile: outputPath, atomically: true, encoding: .utf8)
- 添加到Build Phases:在Xcode的Build Phases里新增一个Run Script,执行:
swift generateFormData.swift
这样每次编译前脚本都会根据最新的数组生成结构体代码,效果和Sourcery类似,只是少了模板的灵活性。
为什么不能直接动态生成?
再啰嗦一句,Swift不像Python那种动态语言,没法在运行时给结构体加属性。而Vapor的Content协议依赖静态的属性定义来做编码解码,所以运行时动态添加的属性根本不会被Vapor识别,代码生成是唯一可行的路径。
这样以后你只要往数组里加元素,编译时就会自动生成对应的变量,完全不用手动修改结构体啦!
内容的提问来源于stack exchange,提问作者Arsen Gaming

