Swift 包的 REPL 支持
swift run
命令有一个新的 --repl
选项,该选项启动 Swift REPL,并支持导入包的库目标。
Swift 发行版带有一个 Swift 语言的 REPL。Swift REPL 是一个用于试验 Swift 代码的绝佳工具,无需创建临时的 Swift 包或 Xcode 项目。可以通过运行不带任何参数的 swift
命令来启动 REPL。
Swift REPL 允许您导入核心库(如 Foundation
、Dispatch
)和系统模块(如 macOS 上的 Darwin
和 Linux 上的 Glibc
)。实际上,REPL 允许您导入任何 Swift 模块,只要它可以使用启动 REPL 时提供的编译器参数正确查找和加载它们。Swift Package Manager 利用此功能,并使用导入包的库目标所需的编译器参数启动 REPL。
示例
让我们使用一些示例来探索新功能
Yams
Yams 是一个用于处理 YAML 的 Swift 包。
克隆该包并使用 swift run --repl
启动 REPL
$ git clone https://github.com/jpsim/Yams
$ cd Yams
$ swift run --repl
这应该编译该包并启动 Swift REPL。让我们尝试使用 dump
方法,该方法将对象转换为 YAML
1> import Yams
2> let yaml = try Yams.dump(object: ["foo": [1, 2, 3, 4], "bar": 3])
yaml: String = "bar: 3\nfoo:\n- 1\n- 2\n- 3\n- 4\n"
3> print(yaml)
bar: 3
foo:
- 1
- 2
- 3
- 4
同样,我们可以使用 load
方法将字符串转换回对象
4> let object = try Yams.load(yaml: yaml)
object: Any? = 2 key/value pairs {
...
}
5> print(object)
Optional([AnyHashable("bar"): 3, AnyHashable("foo"): [1, 2, 3, 4]])
Vapor 的 HTTP
Vapor 项目有一个基于 SwiftNIO 包构建的 HTTP 包。
克隆该包并使用 swift run --repl
启动 REPL
$ git clone https://github.com/vapor/http
$ cd http
$ swift run --repl
让我们使用 HTTPClient
类型发出 GET
请求
1> import HTTP
2> let worker = MultiThreadedEventLoopGroup(numberOfThreads: 1)
3> let client = HTTPClient.connect(hostname: "httpbin.org", on: worker).wait()
4> let httpReq = HTTPRequest(method: .GET, url: "/json")
5> let httpRes = try client.send(httpReq).wait()
6> print(httpRes)
HTTP/1.1 200 OK
Connection: keep-alive
Server: gunicorn/19.9.0
Date: Sun, 30 Sep 2018 21:30:41 GMT
Content-Type: application/json
Content-Length: 429
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Via: 1.1 vegur
{
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
"title": "Sample Slide Show"
}
}
我们可以使用 Foundation 的 JSONSerialization
来解析响应
7> let result = try JSONSerialization.jsonObject(with: httpRes.body.data!) as! NSDictionary
result: NSDictionary = 1 key/value pair {
[0] = {
key = "slideshow"
value = 4 key/value pairs {
[0] = {
key = "slides"
value = 2 elements
}
[1] = {
key = "author"
value = "Yours Truly"
}
[2] = {
key = "title"
value = "Sample Slide Show"
}
[3] = {
key = "date"
value = "date of publication"
}
}
}
}
实现细节
将 REPL 与 Swift 包一起使用需要两条信息才能构建 REPL 参数。第一条信息是为库目标及其依赖项提供头文件搜索路径。对于 Swift 目标,这意味着提供模块的 .swiftmodule
文件的路径;对于 C 目标,我们需要包含目标模块映射文件的目录路径。第二条信息是构建包含所有库目标的共享动态库。这将允许 REPL 在运行时加载所需的符号。SwiftPM 通过合成一个包含根包的所有库目标的特殊产品来实现这一点。此特殊产品仅在使用 --repl
选项时构建,并且不影响其他包管理器操作。
查看实现了此功能的 pull request,了解完整的实现细节!
结论
Swift 包的 REPL 支持将进一步增强 REPL 环境,并为库包作者和使用者提供更轻松的实验体验。该功能可在最新的 trunk snapshot 中试用。如果您发现错误或有增强功能请求,请提交 JIRA!
有问题?
如果您有疑问并有兴趣了解更多信息,请查看 Swift 论坛中的相关讨论主题。