Swift指南
编写此文档时最新的发布版本为Swift 5.2
安装Swift
使用Swift的第一步是安装它和依赖包。请前往Download Swift下载安装。为成功运行接下来的例子,请确保在 $PATH 中成功添加了Swift。
** macOS **
安装Xcode即可,Swift已内嵌在Xcode安装包中 输入 swift --version 查看当前版本:
Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
Target: x86_64-apple-darwin19.4.0
** Ubuntu **
安装clang
$ sudo apt-get install clang
如果您在Linux上将Swift工具链安装到系统根目录以外的目录,则需要使用Swift安装的实际路径运行以下命令:
$ export PATH=/path/to/Swift/usr/bin:"${PATH}"
使用REPL
终端输入 swift 即可打开REPL(Read Eval Print Loop)交互式解释器。
~ swift
Welcome to Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51).
Type :help for assistance.
1>
尝试一下
1> 1 + 2
$R0: Int = 3
2> let greeting = "Hello!"
greeting: String = "Hello!"
3> print(greeting)
Hello!
4> let numbers = [1,2,3]
numbers: [Int] = 3 values {
[0] = 1
[1] = 2
[2] = 3
}
5> for n in numbers.reversed(){
6. print(n)
7. }
3
2
1
8>
尝试导入系统模块
macOS
1> import Darwin
2> arc4random_uniform(10)
$R0: UInt32 = 4
Ubuntu
1> import Glibc
2> random() % 10
$R0: Int32 = 4
Swift包管理器
Swift包管理器提供了一个基于约定的系统,用于构建库和可执行文件,以及在不同的包之间共享代码。
创建包
$ mkdir Hello
$ cd Hello
swift package init
默认情况下,init命令将创建一个库包目录结构:
├── Package.swift
├── README.md
├── Sources
│ └── Hello
│ └── Hello.swift
└── Tests
├── HelloTests
│ └── HelloTests.swift
└── LinuxMain.swift
你可以使用 swift build 来构建一个包。这将下载、解析和编译manifest文件包中提到的依赖项。
$ swift build
Compile Swift Module 'Hello' (1 sources)
测试
$ swift test
Compile Swift Module 'HelloTests' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/HelloPackageTests.xctest/Contents/MacOS/HelloPackageTests
Test Suite 'All tests' started at 2016-08-29 08:00:31.453
Test Suite 'HelloPackageTests.xctest' started at 2016-08-29 08:00:31.454
Test Suite 'HelloTests' started at 2016-08-29 08:00:31.454
Test Case '-[HelloTests.HelloTests testExample]' started.
Test Case '-[HelloTests.HelloTests testExample]' passed (0.001 seconds).
Test Suite 'HelloTests' passed at 2016-08-29 08:00:31.455.
Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'HelloPackageTests.xctest' passed at 2016-08-29 08:00:31.455.
Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.001) seconds
Test Suite 'All tests' passed at 2016-08-29 08:00:31.455.
Executed 1 test, with 0 failures (0 unexpected) in 0.001 (0.002) seconds
编译可执行包
如果目标文件包含一个名为main.swift的文件,则将其视为可执行文件。包管理器将把该文件编译成二进制可执行文件。
在本例中,该包将生成一个名为Hello的可执行文件,输出“Hello, world!”
$ mkdir Hello
$ cd Hello
$ swift package init --type executable
使用swift运行命令来构建和运行可执行文件:
$ swift run Hello
Compile Swift Module 'Hello' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/Hello
Hello, world!
注意:由于此包中只有一个可执行文件,我们可以从swift运行命令中省略可执行文件的名称。
您还可以通过运行swift build命令编译包,然后从.build目录运行二进制文件:
$ swift build
Compile Swift Module 'Hello' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/Hello
$ .build/x86_64-apple-macosx10.10/debug/Hello
Hello, world!
下一步,让我们在一个新的源文件中定义一个新的 sayHello(name:) 函数,并让可执行文件调用它,而不是直接调用 print(_😃 。
处理多个源文件
在 Sources/Hello 目录中新建 Greeter.swift,并输入以下代码:
func sayHello(name: String) {
print("Hello, \(name)!")
}
sayHello(name:) 函数接受一个字符串参数并在之前打印“Hello”问候语,用函数参数替换单词“World”。
现在,再次打开 main.swift,将现有内容替换为以下代码:
if CommandLine.arguments.count != 2 {
print("Usage: hello NAME")
} else {
let name = CommandLine.arguments[1]
sayHello(name: name)
}
现在main.swift不再像以前那样使用硬编码的名称,而是从命令行参数中读取。 与直接调用 print(_😃 不同,main.swift 现在调用 sayHello(name:) 方法。 因为该方法是 Hello 模块的一部分,所以不需要 import 语句:
$ swift run Hello `whoami`
使用LLDB调试器
使用LLDB调试器可以逐步运行Swift程序,设置断点,并检查和修改程序状态。
新建 Factorial.swift:
func factorial(n: Int) -> Int {
if n <= 1 { return n }
return n * factorial(n: n - 1)
}
let number = 4
print("\(number)! is equal to \(factorial(n: number))")
使用swiftc产生调试信息:
$ swiftc -g Factorial.swift
$ ls
Factorial.dSYM
Factorial.swift
Factorial*
不直接运行Factorial程序,而是通过LLDB调试器将其作为命令行参数传递给LLDB命令来运行它。
$ lldb Factorial
(lldb) target create "Factorial"
Current executable set to 'Factorial' (x86_64).
这将启动一个交互式控制台用于运行LLDB命令。
更多调试技巧可参考LLDB Tutorial
在 factorial(n:) 函数的第2行中使用 breakpoint Set (b) 命令设置一个断点,以便在每次执行该函数时让进程中断。
(lldb) b 2
Breakpoint 1: where = Factorial`Factorial.factorial (Swift.Int) -> Swift.Int + 12 at Fa
使用 Run (r) 命令运行进程。该进程将在 factorial(n:) 函数的调用位置停止。
(lldb) r
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14dfdf, 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2
1 func factorial(n: Int) -> Int {
-> 2 if n <= 1 { return n }
3 return n * factorial(n: n - 1)
4 }
5
6 let number = 4
7 print("\(number)! is equal to \(factorial(n: number))")
使用 print (p) 命令检查n参数的值。
(lldb) p n
(Int) $R0 = 4
print 命令也可以计算Swift表达式。
(lldb) p n * n
(Int) $R1 = 16
使用 backtrace (bt) 命令显示导致调用 factorial(n:) 的帧。
(lldb) bt
* thread #1: tid = 0x14e393, 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=4) -> Swift.Int + 12 at Factorial.swift:2
frame #1: 0x0000000100000daf Factorial`main + 287 at Factorial.swift:7
frame #2: 0x00007fff890be5ad libdyld.dylib`start + 1
frame #3: 0x00007fff890be5ad libdyld.dylib`start + 1
使用 continue (c) 命令继续这个过程,直到再次命中断点为止。
(lldb) c
Process 40246 resuming
Process 40246 stopped
* thread #1: tid = 0x14e393, 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000e7c Factorial`Factorial.factorial (n=3) -> Swift.Int + 12 at Factorial.swift:2
1 func factorial(n: Int) -> Int {
-> 2 if n <= 1 { return n }
3 return n * factorial(n: n - 1)
4 }
5
6 let number = 4
7 print("\(number)! is equal to \(factorial(n: number))")
再次使用 print (p) 命令检查第二次调用 factorial(n:) 时n参数的值。
(lldb) p n
(Int) $R2 = 3
使用 breakpoint disable (br di) 命令禁用所有断点,使用 continue (c) 命令运行进程,直到它退出。
(lldb) br di
All breakpoints disabled. (1 breakpoints)
(lldb) c
Process 40246 resuming
4! is equal to 24
Process 40246 exited with status = 0 (0x00000000)