Swift语法全面解析

Swift介绍

Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。 swift 是一种安全,快速和互动的编程语言。 swift 支持代码预览(playgrounds),这个特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。

Swift 通过采用现代编程模式来避免大量常见编程错误:

变量始终在使用前初始化。 检查数组索引超出范围的错误。 检查整数是否溢出。 可选值确保明确处理 nil 值。 内存被自动管理。 错误处理允许从意外故障控制恢复。

基础部分

常量和变量

声明常量和变量, 常量和变量必须在使用前声明,使用 let 来声明常量,使用 var 来声明变量。 示例:

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

// 类型注解
var welcomeMessage: String

注释

单行注释双正斜杠(//), 多行注释(/* 多行的 */)。Swift 的多行注释可以嵌套在其它的多行注释之中。 示例:

// 这是一个注释

/* 这也是一个注释,
但是是多行的 */

/* 这是第一个多行注释的开头
/* 这是第二个被嵌套的多行注释 */
这是第一个多行注释的结尾 */

分号

Swift 并不强制要求你在每条语句的结尾处使用分号(;)。 同一行内写多条独立的语句必须用分号分隔。

let cat = " "; print(cat)
// 输出“ ”

标识符

标识符就是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字。构成标识符的字母均有一定的规范,Swift语言中标识符的命名规则如下:

区分大小写,Myname与myname是两个不同的标识符;

标识符首字符可以以下划线(_)或者字母开始,但不能是数字;

标识符中其他字符可以是下划线(_)、字母或数字。

例如: userName、User_Name、_sys_val、身高等为合法的标识符,而2mail、room#和class为非法的标识符。

注意:Swift中的字母采用的是Unicode编码。Unicode叫做统一编码制,它包含了亚洲文字编码,如中文、日文、韩文等字符,甚至是我们在聊天工具中使用的表情符号

如果一定要使用关键字作为标识符,可以在关键字前后添加重音符号(`),例如:

let `class` = "xiaobai"

关键字

关键字是类似于标识符的保留字符序列,除非用重音符号(`)将其括起来,否则不能用作标识符。关键字是对编译器具有特殊意义的预定义保留标识符。常见的关键字有以下4种。 与声明有关的关键字

class deinit enum extension
func import init internal
let operator private protocol
public static struct subscript
typealias var

与语句有关的关键字

break case continue default
do else fallthrough for
if in return switch
where while

表达式和类型关键字

as dynamicType false is
nil self Self super
true _COLUMN_ _FILE_ _FUNCTION_
_LINE_

在特定上下文中使用的关键字

associativity convenience dynamic didSet
final get infix inout
lazy left mutating none
nonmutating optional override postfix
precedence prefix Protocol required
right set Type unowned
weak willSet

Swift 空格

Swift对空格的使用有一定的要求。 在Swift中,运算符不能直接跟在变量或常量的后面。例如下面的代码会报错:

let a= 1 + 2

错误信息是:

error: prefix/postfix '=' is reserved

意思大概是等号直接跟在前面或后面这种用法是保留的。

下面的代码还是会报错(继续注意空格):

let a = 1+ 2

错误信息是:

error: consecutive statements on a line must be separated by ';'

这是因为Swift认为到1+这个语句就结束了,2就是下一个语句了。

只有这样写才不会报错:

let a = 1 + 2; // 编码规范推荐使用这种写法
let b = 3+4 // 这样也是OK的

整数、浮点数

统一使用 Int 可以提高代码的可复用性,避免不同类型数字之间的转换, 并且匹配数字的类型推断。 示例:

let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型

类型安全和类型推断

Swift 是一门类型安全的语言,这意味着 Swift 可以让你清楚地知道值的类型。 如果你没有显式指定类型,Swift 会使用类型推断来选择合适的类型。(int、double)。 示例:

let meaningOfLife = 42
// meaningOfLife 会被推测为 Int 类型

let pi = 3.14159
// pi 会被推测为 Double 类型

数值型字面量、数值型类型转换

示例:

let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17
let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17

类型别名

类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名。 示例:

typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound 现在是 0

布尔值

示例:

let orangesAreOrange = true
let turnipsAreDelicious = false

元组

元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。 示例:

let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")

可选类型

使用可选类型(optionals)来处理值可能缺失的情况。可选类型表示两种可能:或者有值, 你可以解析可选类型访问这个值, 或者根本没有值。 示例:

var serverResponseCode: Int? = 404
// serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil
// serverResponseCode 现在不包含值

错误处理

错误处理,应对程序执行中可能会遇到的错误条件。 示例:

func makeASandwich() throws {
 // ...
}

do {
 try makeASandwich()
 eatASandwich()
} catch SandwichError.outOfCleanDishes {
 washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
 buyGroceries(ingredients)
}

断言和先决条件

断言和先决条件,是在运行时所做的检查。

let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0,所以断言会触发

基本运算符

Swift 支持大部分标准 C 语言的运算符,还提供了 C 语言没有的区间运算符,例如 a..<b 或 a...b。 赋值运算符,算术运算符,组合赋值运算符,比较运算符,三元运算符,空合运算符,区间运算符,逻辑运算符

运算符分为一元、二元和三元运算符。 闭区间运算符(a…b)定义一个包含从 a 到 b(包括 a 和 b)的所有值的区间。 半开区间运算符(a..<b)定义一个从 a 到 b 但不包括 b 的区间。 闭区间操作符有另一个表达形式,可以表达往一侧无限延伸的区间,(a…,…b)。 示例:

let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
 print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian
// 第 4 个人叫 Jack

字符串和字符

字符串字面量,字符串插值,计算字符数量,访问和修改字符串,子字符串,比较字符串

初始化空字符串,字符串可变性,字符串是值类型,连接字符串和字符(+,+=)。 使用字符,可通过 for-in 循环来遍历字符串,获取字符串中每一个字符的值。 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。可以在已有字符串中插入常量、变量、字面量和表达式从而形成更长的字符串。 Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。 示例:

// 多行字符串字面量
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""

// 下面两个字符串其实是一样的
let singleLineString = "These are the same."
let multilineString = """
These are the same.
"""

// 字符串插值
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message 是 "3 times 2.5 is 7.5"

// 计算字符数量
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// 打印输出“the number of characters in cafe is 4”

var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 两个字符串均为空并等价。

let catCharacters: [Character] = ["C", "a", "t", "!"]
let catString = String(catCharacters)
print(catString)
// 打印输出:“Cat!”

集合类型

Swift 语言提供数组(Array)、集合(Set)和字典(Dictionary)三种基本的集合类型用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。 集合的可变性,数组(Arrays),集合(Sets),集合操作,字典

数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。 集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。 集合操作,可以高效地完成集合的一些基本操作,比如把两个集合组合到一起,判断两个集合共有元素,或者判断两个集合是否全包含,部分包含或者不相交。 字典是一种无序的集合,它存储的是键值对之间的关系,其所有键的值需要是相同的类型,所有值的类型也需要相同。每个值(value)都关联唯一的键(key),键作为字典中这个值数据的标识符。 示例:

// 集合
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// 打印“someInts is of type [Int] with 0 items.”

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 是一种 [Double] 数组,等价于 [0.0, 0.0, 0.0]

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles 被推断为 [Double],等价于 [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 被推断为 [Double],等价于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

// enumerated() 方法遍历数组
var shoppingList: [String] = ["Eggs", "Milk"]
for (index, value) in shoppingList.enumerated() {
 print("Item \(String(index + 1)): \(value)")
}

控制流

For-In 循环,While 循环(Repeat-While),条件语句,控制转移语句,提前退出(guard),检测 API 可用性

像 if 语句一样,guard 的执行取决于一个表达式的布尔值。我们可以使用 guard 语句来要求条件必须为真时,以执行 guard 语句后的代码。不同于 if 语句,一个 guard 语句总是有一个 else 从句,如果条件不为真则执行 else 从句中的代码。 Swift 内置支持检查 API 可用性,编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。 示例:

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
 print("Hello, \(name)!")
}

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
 print("\(animalName)s have \(legCount) legs")
}

// repeat-while 循环的一般格式
repeat {
 statements
} while condition


// 提前退出
func greet(person: [String: String]) {
 guard let name = person["name"] else {
 return
 }

 print("Hello \(name)!")

 guard let location = person["location"] else {
 print("I hope the weather is nice near you.")
 return
 }

 print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// 输出“Hello John!”
// 输出“I hope the weather is nice near you.”
greet(person: ["name": "Jane", "location": "Cupertino"])
// 输出“Hello Jane!”
// 输出“I hope the weather is nice in Cupertino.”

函数

函数的定义与调用,函数参数与返回值,函数参数标签和参数名称,函数类型,嵌套函数

可选元组返回类型。 定义一个输入输出参数时,在参数定义前加 inout 关键字。 示例:

// 函数
func greet(person: String) -> String {
 let greeting = "Hello, " + person + "!"
 return greeting
}

func greet(person: String, from hometown: String) -> String {
 return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”

// 可选元组返回类型
func minMax(array: [Int]) -> (min: Int, max: Int)? {
 if array.isEmpty { return nil }
 var currentMin = array[0]
 var currentMax = array[0]
 for value in array[1..<array.count] {
 if value < currentMin {
 currentMin = value
 } else if value > currentMax {
 currentMax = value
 }
 }
 return (currentMin, currentMax)
}

// 隐式返回的函数
func greeting(for person: String) -> String {
 "Hello, " + person + "!"
}
print(greeting(for: "Dave"))
// 打印 "Hello, Dave!

// 参数标签
func greet(person: String, from hometown: String) -> String {
 return "Hello \(person)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// 打印“Hello Bill! Glad you could visit from Cupertino.”

闭包

闭包是自包含的函数代码块,可以在代码中被传递和使用。与一些编程语言中的匿名函数(Lambdas)比较相似。 闭包表达式,尾随闭包,值捕获,闭包是引用类型,逃逸闭包(@escaping),自动闭包

如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数,将这个闭包替换成为尾随闭包的形式很有用。 闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。 示例:

// 闭包表达式语法
{ (parameters) -> return type in
 statements
}

// 尾随闭包
let digitNames = [
 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
 (number) -> String in
 var number = number
 var output = ""
 repeat {
 output = digitNames[number % 10]! + output
 number /= 10
 } while number > 0
 return output
}
// strings 常量被推断为字符串类型数组,即 [String]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]

// 值捕获
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
 var runningTotal = 0
 func incrementer() -> Int {
 runningTotal += amount
 return runningTotal
 }
 return incrementer
}

// 自动闭包,延迟求值
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出“5”

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出“5”

print("Now serving \(customerProvider())!")
// Prints "Now serving Chris!"
print(customersInLine.count)
// 打印出“4”

枚举

使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内。 枚举语法,使用 Switch 语句匹配枚举值,枚举成员的遍历,关联值,原始值(默认值),递归枚举(indirect)

可以定义 Swift 枚举来存储任意类型的关联值,每个枚举成员的关联值类型可以各不相同。 示例:

// 枚举语法
enum SomeEnumeration {
 // 枚举定义放在这里
}

enum CompassPoint {
 case north
 case south
 case east
 case west
}

enum Planet {
 case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

let somePlanet = Planet.earth
switch somePlanet {
case .earth:
 print("Mostly harmless")
default:
 print("Not a safe place for humans")
}
// 打印“Mostly harmless”

// 关联值
enum Barcode {
 case upc(Int, Int, Int, Int)
 case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
 print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
 print("QR code: \(productCode).")
}
// 打印“QR code: ABCDEFGHIJKLMNOP.”

// 递归枚举
indirect enum ArithmeticExpression {
 case number(Int)
 case addition(ArithmeticExpression, ArithmeticExpression)
 case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
// (5 + 4) * 2

func evaluate(_ expression: ArithmeticExpression) -> Int {
 switch expression {
 case let .number(value):
 return value
 case let .addition(left, right):
 return evaluate(left) + evaluate(right)
 case let .multiplication(left, right):
 return evaluate(left) * evaluate(right)
 }
}

print(evaluate(product))
// 打印“18”

结构体和类

结构体和类对比,结构体和枚举是值类型,类是引用类型

结构体和类作为一种通用而又灵活的结构,成为了人们构建代码的基础。你可以使用定义常量、变量和函数的语法,为你的结构体和类定义属性、添加方法。 示例:

                

文章来源:

Author:白菜
link:https://blog.baicai.me/article/2021/swift-basic-syntax/