cnswift.org/the-basics
基础内容
Swift 是⼀门全新的⽤于开发 iOS, OS X 以及 watchOS 应⽤的编程语⾔。不过,如果你有 C 或
者Objective-C 语⾔开发经验的话,Swift 的许多地⽅都会让你感到熟悉。
Swift 为所有 C 和 Objective-C 的类型提供了⾃⼰的版本,包括整型值的 Int ,浮点数值的
Double 和 Float ,布尔量值的 Bool ,字符串值的 String 。如同集合类型中描述的那样,
Swift 同样也为三个主要的集合类型提供了更⾼效的版本, Array , Set 和 Dictionary 。
和 C ⼀样,Swift ⽤变量存储和调⽤值,通过变量名来做区分。Swift 中也⼤量采⽤了值不可变
的变量。它们就是所谓的常量,但是它们⽐ C 中的常量更加给⼒。当你所处理的值不需要更改
时,使⽤常量会让你的代码更加安全、简洁地表达你的意图。
除了我们熟悉的类型以外,Swift 还增加了 Objective-C 中没有的类型,⽐如元组。元组允许你
来创建和传递⼀组数据。你可以利⽤元组在⼀个函数中以单个复合值的形式返回多个值。
Swift 还增加了可选项,⽤来处理没有值的情况。可选项意味着要么“这⾥有⼀个值,它等
于 x”要么“这⾥根本没有值”。可选项类似于 Objective-C 中的 nil 指针,但是不只是类,可选项
也可以⽤在所有的类型上。可选项⽐ Objective-C 中的 nil 指针更安全、更易读,他也是 Swift
语⾔中许多重要功能的核⼼。
可选项充分证明了 Swift 是⼀门类型安全的语⾔。Swift 帮助你明确代码可以操作值的类型。如
果你的⼀段代码预期得到⼀个 String ,类型会安全地阻⽌你不⼩⼼传⼊ Int 。在开发过程中,
这个限制能帮助你在开发过程中更早地发现并修复错误。
常量和变量
常量和变量把名字(例如 maximumNumberOfLoginAttempts 或者 welcomeMessage )和
⼀个特定类型的值(例如数字 10 或者字符串 “Hello”)关联起来。常量的值⼀旦设置好便不能
再被更改,然⽽变量可以在将来被设置为不同的值。
声明常量和变量
常量和变量必须在使⽤前被声明,使⽤关键字 let 来声明常量,使⽤关键字 var 来声明变量。
这⾥有⼀个如何利⽤常量和变量记录⽤户登录次数的栗⼦:
1
2
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
这段代码可以读作:
“声明⼀个叫做 maximumNumberOfLoginAttempts 的新常量,并设置值为 10 。然后声明⼀
个叫做 currentLoginAttempt 的新变量, 并且给他⼀个初始值 0。。”
1/20
在这个栗⼦中,登录次数允许的最⼤值被声明为⼀个常量,因为最⼤值永远不会更改。当前尝
试登录的次数被声明为⼀个变量,因为这个值在每次登录尝试失败之后会递增。
你可以在⼀⾏中声明多个变量或常量,⽤逗号分隔:
1 var x = 0.0, y = 0.0, z = 0.0
注意
在你的代码中,如果存储的值不会改变,请用 let 关键字将之声明为一个常量。只
有储存会改变的值时才使用变量。
类型标注
你可以在声明⼀个变量或常量的时候提供类型标注,来明确变量或常量能够储存值的类型。添
加类型标注的⽅法是在变量或常量的名字后边加⼀个冒号,再跟⼀个空格,最后加上要使⽤的
类型名称。
下⾯这个栗⼦给⼀个叫做 welcomeMessage 的变量添加了类型标注,明确这个变量可以存储
String 类型的值。
1 var welcomeMessage: String
声明中的冒号的意思是“是…类型”,所以上⾯的代码可以读作:
“声明⼀个叫做 welcomMessage 的变量,他的类型是 String ”
我们说“类型是 String ”就意味着“可以存储任何 String 值”。也可以理解为“这类东⻄”(或者“这
种东⻄”)可以被存储进去。
现在这个 welcomeMessage 变量就可以被设置到任何字符串中⽽不会报错了:
1 welcomeMessage = "Hello"
你可以在⼀⾏中定义多个相关的变量为相同的类型,⽤逗号分隔,只要在最后的变量名字后边
加上类型标注。
1 var red, green, blue: Double
注意
实际上,你并不需要经常使用类型标注。如果你在定义一个常量或者变量的时候就
给他设定一个初始值,那么 Swift 就像类型安全和类型推断中描述的那样,几乎都
可以推断出这个常量或变量的类型。在上面 welcomeMessage 的栗子中,没有提供
初始值,所以 welcomeMessage 这个变量使用了类型标注来明确它的类型而不是通
过初始值的类型推断出来的。
2/20
命名常量和变量
常量和变量的名字⼏乎可以使⽤任何字符,甚⾄包括 Unicode 字符:
1
2
3
let π = 3.14159
let 你好 = "你好世界"
let ️️ = "dogcow"
常量和变量的名字不能包含空⽩字符、数学符号、箭头、保留的(或者⽆效的)Unicode 码
位、连线和制表符。也不能以数字开头,尽管数字⼏乎可以使⽤在名字其他的任何地⽅。
⼀旦你声明了⼀个确定类型的常量或者变量,就不能使⽤相同的名字再次进⾏声明,也不能让
它改存其他类型的值。常量和变量之间也不能互换。
注意
如果你需要使用 Swift 保留的关键字来给常量或变量命名,可以使用反引号( ` )
包围它来作为名称。总之,除非别无选择,避免使用关键字作为名字除非你确实别
无选择。
你可以把现有变量的值更改为其他相同类型的值。在这个栗⼦中 friendlyWelcome 的值从
“Hello!” 改变为 “Bonjour!”
1
2
3
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome 现在是 "Bonjour!"
不同于变量,常量的值⼀旦设定则不能再被改变。尝试这么做将会在你代码编译时导致报错:
1
2
3
let languageName = "Swift"
languageName = "Swift++"
// this is a compile-time error - languageName cannot be
changed
输出常量和变量
你可以使⽤ print(_:separator:terminator:) 函数来打印当前常量和变量中的值。
1
2
print(friendlyWelcome)
// 输出 "Bonjour!"
print(_:separator:terminator:) 是⼀个⽤来把⼀个或者多个值⽤合适的⽅式输出的全局函数。
⽐如说,在 Xcode 中 print(_:separator:terminator:) 函数输出的内容会显⽰在Xcode的
“console” ⾯板上。 separator 和 terminator 形式参数有默认值,所以你可以在调⽤这个函数
3/20
的时候忽略它们。默认来说,函数通过在⾏末尾添加换⾏符来结束输出。要想输出不带换⾏符
的值,那就传⼀个空的换⾏符作为结束——⽐如说, print(someValue, terminator: "") 。更多
关于带有默认值的形式参数信息,⻅默认形式参数值。
Swift 使⽤字符串插值 的⽅式来把常量名或者变量名当做占位符加⼊到更⻓的字符串中,然后
让 Swift ⽤常量或变量的当前值替换这些占位符。将常量或变量名放⼊圆括号中并在括号前使
⽤反斜杠将其转义:
1
2
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出 "The current value of friendlyWelcome is Bonjour!"
注意
字符串插值中描述了你可以使用字符串插值的所有选项。
注释
使⽤注释来将不需要执⾏的⽂本放⼊的代码当中,作为标记或者你⾃⼰的提醒。当 Swift 编译
器在编译代码的时候会忽略掉你的注释。
Swift 中的注释和 C 的注释基本相同。单⾏注释⽤两个斜杠开头( // ):
1 // 这是⼀个注释
多⾏的注释以⼀个斜杠加⼀个星号开头( /* ),以⼀个星号加斜杠结尾( */ )。
1
2
/* this is also a comment,
but written over multiple lines */
和 C 中的多⾏注释不同的是, Swift 语⾔中的多⾏的注释可以内嵌在其它的多⾏注释之中,你
可以在多⾏注释中先开启⼀个注释块,接着再开启另⼀个注释块。然后关闭第⼆个注释块,再
关闭第⼀个注释块。
/* 这是第⼀个多⾏注释的开头
/* 这是第⼆个嵌套在内的注释块 */
这是第⼀个注释块的结尾*/
1
2
3
内嵌多⾏注释,可以便捷地注释掉⼀⼤段代码块,即使这段代码块中已经有了多⾏注释。
分号
和许多其他的语⾔不同,Swift 并不要求你在每⼀句代码结尾写分号( ; ),当然如果你想写的
话也没问题。总之,如果你想在⼀⾏⾥写多句代码,分号还是需要的。
4/20
1
2
let cat = "️"; print(cat)
// 输出 "️"
整数
整数就是没有⼩数部分的数字,⽐如 42 和 -23 。整数可以是有符号(正,零或者负),或
者⽆符号(正数或零)。
Swift 提供了 8,16,32 和 64 位编码的有符号和⽆符号整数,这些整数类型的命名⽅式和 C
相似,例如 8 位⽆符号整数的类型是 UInt8 ,32 位有符号整数的类型是 Int32 。与 Swift 中的
其他类型相同,这些整数类型也⽤开头⼤写命名法。
整数范围
你可以通过 min 和 max 属性来访问每个整数类型的最⼩值和最⼤值:
let minValue = UInt8.min // 最⼩值是 0, 值的类型是 UInt8
let maxValue = UInt8.max // 最⼤值是 255, 值得类型是
1
2
UInt8
这些属性的值都是⾃适应⼤⼩的数字类型(⽐如说上边栗⼦⾥的 UInt8 )并且因此可以在表达
式中与在其他相同类型值同⽤。
Int
在⼤多数情况下,你不需要在你的代码中为整数设置⼀个特定的⻓度。Swift 提供了⼀个额外
的整数类型: Int ,它拥有与当前平台的原⽣字相同的⻓度。
在32位平台上, Int 的⻓度和 Int32相同。
在64位平台上, Int 的⻓度和 Int64 相同。
除⾮你需操作特定⻓度的整数,否则请尽量在代码中使⽤ Int 作为你的整数的值类型。这样能
提⾼代码的统⼀性和兼容性,即使在 32 位的平台上, Int 也可以存 -2,147,483,648到
2,147,483,647之间的任意值,对于⼤多数整数区间来说完全够⽤了。
UInt
Swift 也提供了⼀种⽆符号的整数类型, UInt ,它和当前平台的原⽣字⻓度相同。
在32位平台上, UInt ⻓度和 UInt32 ⻓度相同。
在64位平台上, UInt ⻓度和 UInt64 ⻓度相同。
5/20
注意
只在的确需要存储一个和当前平台原生字长度相同的无符号整数的时候才使用
UInt 。其他情况下,推荐使用 Int ,,即使已经知道存储的值都是非负的。如同类型
安全和类型推断中描述的那样,统一使用 Int 会提高代码的兼容性,同时可以避免
不同数字类型之间的转换问题,也符合整数的类型推断。
浮点数
浮点数是有⼩数的数字,⽐如 3.14159 , 0.1 , 和 -273.15。
浮点类型相⽐整数类型来说能表⽰更⼤范围的值,可以存储⽐ Int 类型更⼤或者更⼩的数字。
Swift 提供了两种有符号的浮点数类型。
Double代表 64 位的浮点数。
Float 代表 32 位的浮点数。
注意
Double 有至少 15 位数字的精度,而 Float 的精度只有 6 位。具体使用哪种浮点类
型取决于你代码需要处理的值范围。在两种类型都可以的情况下,推荐使用
Double 类型。
类型安全和类型推断
Swift 是⼀门类型安全的语⾔。类型安全的语⾔可以让你清楚地知道代码可以处理的值的类
型。如果你的⼀部分代码期望获得 String ,,你就不能错误的传给它⼀个 Int 。。
因为 Swift 是类型安全的,他在编译代码的时候会进⾏类型检查,任何不匹配的类型都会被标
记为错误。这会帮助你在开发阶段更早的发现并修复错误。
当你操作不同类型的值时,类型检查能帮助你避免错误。当然,这并不意味着你得为每⼀个常
量或变量声明⼀个特定的类型。如果你没有为所需要的值进⾏类型声明,Swift 会使⽤类型推
断的功能推断出合适的类型。通过检查你给变量赋的值,类型推断能够在编译阶段⾃动的推断
出值的类型。
因为有了类型推断,Swift 和 C 以及 Objective-C 相⽐,只需要少量的类型声明。其实常量和
变量仍然需要明确的类型,但是⼤部分的声明⼯作 Swift 会帮你做。
在你为⼀个变量或常量设定⼀个初始值的时候,类型推断就显得更加有⽤。它通常在你声明⼀
个变量或常量同时设置⼀个初始的字⾯量(⽂本)时就已经完成。(字⾯量就是会直接出现在
你代码中的值,⽐如下边代码中的 42 和 3.14159 。)
举个栗⼦,如果你给⼀个新的常量设定⼀个 42 的字⾯量,⽽且没有说它的类型是什么,Swift
会推断这个常量的类型是 Int ,因为你给这个常量初始化为⼀个看起来像是⼀个整数的数字。
6/20
1
2
let meaningOfLife = 42
// meaningOfLife is inferred to be of type
Int
同样,如果你没有为⼀个浮点值的字⾯量设定类型,Swift 会推断你想创建⼀个 Double 。。
1
2
let pi = 3.14159
// pi is inferred to be of type
Double
Swift 在推断浮点值的时候始终会选择 Double (⽽不是 Float )。
如果你在⼀个表达式中将整数和浮点数结合起来, Double会从内容中被推断出来。
1
2
let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type
Double
这字⾯量 3 没有显式的声明它的类型,但因为后边有⼀个浮点类型的字⾯量,所以这个类型就
被推断为 Double 。
数值型字⾯量
整数型字⾯量可以写作:
⼀个⼗进制数,没有前缀
⼀个⼆进制数,前缀是 0b
⼀个⼋进制数,前缀是 0o
⼀个⼗六进制数,前缀是 0x
下⾯的这些所有整数字⾯量的⼗进制值都是 17 :
1
2
3
4
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
浮点字⾯量可以是⼗进制(没有前缀)或者是⼗六进制(前缀是 0x )。⼩数点两边必须有⾄
少⼀个⼗进制数字(或者是⼗六进制的数字)。⼗进制的浮点字⾯量还有⼀个可选的指数,⽤
⼤写或⼩写的 e 表⽰;⼗六进制的浮点字⾯量必须有指数,⽤⼤写或⼩写的 p 来表⽰。
⼗进制数与 exp 的指数,结果就等于基数乘以 10 :
exp
1.25e2意味着 1.25 x 10 , 或者 125.0 .
2
-2
7/20
1.25e-2 意味着 1.25 x 10 , 或者 0.0125 .
-2
⼗六进制数与 exp 指数,结果就等于基数乘以2 :
exp
0xFp2 意味着 15 x 2 , 或者 60.0 .
0xFp-2 意味着 15 x 2 , 或者 3.75 .
-2
2
下⾯的这些浮点字⾯量的值都是⼗进制的 12.1875 :
1
2
3
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
数值型字⾯量也可以增加额外的格式使代码更加易读。整数和浮点数都可以添加额外的零或者
添加下划线来增加代码的可读性。下⾯的这些格式都不会影响字⾯量的值。
1
2
3
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数值类型转换
通常来讲,即使我们知道代码中的整数变量和常量是⾮负的,我们也会使⽤ Int 类型。经常使
⽤默认的整数类型可以确保你的整数常量和变量可以直接被复⽤并且符合整数字⾯量的类型推
测。
只有在特殊情况下才会使⽤整数的其他类型,例如需要处理外部⻓度明确的数据或者为了优化
性能、内存占⽤等其他必要情况。在这些情况下,使⽤指定⻓度的类型可以帮助你及时发现意
外的值溢出和隐式记录正在使⽤数据的本质。
整数转换
不同整数的类型在变量和常量中存储的数字范围是不同的。 Int8 类型的常量或变量可以存储的
数字范围是 -128~127,⽽ UInt8 类型的常量或者变量能存储的数字范围是 0~255 。如果数字
超出了常量或者变量可存储的范围,编译的时候就会报错:
1
2
3
4
5
let cannotBeNegative: UInt8 = -1
// UInt8 cannot store negative numbers, and so this will report an
error
let tooBig: Int8 = Int8.max + 1
// Int8 cannot store a number larger than its maximum value,
// and so this will also report an error
因为每个数值类型可存储的值的范围不同,你必须根据不同的情况进⾏数值类型的转换。这种
选择性使⽤的⽅式可以避免隐式转换的错误并使你代码中的类型转换意图更加清晰。
8/20