Swift 进阶(一)基础语法

Swift简介

在学习Swift之前,我们先来了解下什么是Swift

Swift是Apple在2014年6月WWDC发布的全新编程语言,中文名和LOGO是”雨燕“

Swift之父是Chris Lattner,也是Clang编译器的作者,LLVM项目的主要发起人

Swift版本

Swift历时七年,从Swift 1.*更新到Swift 5.*,经历了多次重大改变,ABI终于稳定

API(Application Programming Interface):应用程序编程接口

  • 源代码和库之间的接口

ABI(Application Binary Interface):应用程序二进制接口

  • 应用程序和操作系统之间的底层接口
  • 涉及的内容有:目标文件格式、数据类型的大小/布局/对齐,函数调用约定等

Swift是完全开源的,下载地址:https://github.com/apple/swift

Swift编译原理

LLVM编译器

LLVM编译器一般分为前端和后端

  • 前端:主要进行词法分析,生成语法树
  • 后端:生成对应平台的二进制代码

编译流程

我们知道OC的前端是通过Clang进行编译的,Swift的前端是通过swiftc来编译的

不同语言的前端可能不同,但最终都会通过编译器的后端生成对应平台的二进制代码

-w727

整个编译流程如下图所示

-w525

  • Swift Code:我们编写的Swift代码
  • Swift AST:Swift语法树
  • Raw Swift IL:Swift特有的中间代码
  • Canonical Swift IL:更简洁的Swift特有的中间代码
  • LLVM IR:LLVM的中间代码
  • Assembly:汇编代码
  • Executable:二进制代码

关于Swift编译流程的详细讲解可以参考以下网址:https://swift.org/swift-compiler/#compiler-architecture

swiftc

我们打开终端,输入swiftc -help,会打印出相关指令,这也说明了swiftc已经存在于Xcode中

-w890

我们可以在应用程序中找到Xcode,然后右键显示包内容,通过该路径找到swiftc

路径:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

-w1175
-w788

swiftc的基本操作演练

下面我们可以通过一些swiftc的一些基本操作来了解

1.我们先新建一个Swift的命令行项目

-w1399
-w1076

2.然后打开终端,cdmain.swift路径

-w890

3.然后我们输入swiftc -dump-ast main.swift,来查看下生成的语法树

-w890

4.我们还可以输入swiftc -emit-sil main.swift生成最简洁的SIL代码

-w890

5.我们还可以输入swiftc -emit-ir main.swift生成LLVM IR中间代码

-w890

6.我们还可以输入swiftc -emit-assembly main.swift生成汇编代码

-w890

Swift基础语法

Swift中打印输入:print("Hello World")

Swift中一句代码是可以省略分号的,但是如果多句代码写在一行,需要用分号隔开

Swift不用编写main函数,会以全局范围内的首句可执行代码作为入口来执行

通过反汇编我们可以看到底层会执行main函数

-w1084

常量和变量

常量:

1.用let定义常量,常量只能赋值一次

不用特意指明类型,编译器会自动进行推断

let a: Int = 10
let b = 20

2.它的值不要求在编译过程中确定,但使用之前必须赋值一次

这样写确定了a的类型,之后再去赋值,也不会报错

let a: Int
a = 10

用函数给常量赋值也可以,函数是在运行时才会确定值的,所以只要保证使用之前赋值了就行

func getNumber() -> Int {
    return 10
}

let a: Int
a = getNumber()

如果没有给a确定类型,也没有一开始定义的时候赋值,就会像下面这样报错

-w643

变量:

1.用var定义变量

var b = 20
b = 30

2.常量、变量在初始化之前,都不能使用

-w644

注释

1.Swift中有单行注释和多行注释

注释之间嵌套也没有问题

// 单行注释

/*
 多行注释
 /*
 多行注释
 */
 
 /*
 // 注释嵌套
 */

2.Playground里的注释支持Markup语法(同Markdown)

Markup语法只在Playground里有效,在项目中无效

//: # 一级标题

/*:
 ## 基础语法
 */

可以通过Editor -> Show Raw Markup来预览

-w299

预览的效果如下

-w369

标识符

1.标识符(比如常量名、变量名、函数名)几乎可以使用任何字符

let 📒 = 5
var 😁 = 10

func 👽() {
    
}

标识符不能以数字开头,不能包含空白字符、制表符、箭头等特殊字符

-w649

常见数据类型

常见类型

  • 值类型
    • 枚举(enum): Optional
    • 结构体(struct): Bool、Double、Float、Int、Character、String、Array、Dictionary、Set
  • 引用类型
    • 类(class)

可以通过command+control进入到该类型的API中查看

例如Int类型

-w757

整数类型

整数类型:Int8、Int16、Int32、Int64、UInt8、UInt16、UInt32、UInt64

在32bit平台,Int等于Int32;在64bit平台,Int等于Int64

整数的最值:UInt8.max,Int16.min

一般情况下,都是直接使用Int即可

let a: Int8 = 5

浮点类型

Float:32位,精度只有6位

Double:64位,精度至少15位

浮点型不指明类型默认就是Double

let a: Float = 2.0
let b = 3.0

字面量

字面量就是指这个量本身,就是一个固定值的表示法

下面这些都是字面量

Bool布尔

一般用Bool类型来表示是否的判断,是为true,否为false

let bool = true 
字符串、字符

字符串的写法

let string = "hello"

字符类型要写上Character,否则会被认为是字符串

字符可存储ASCII字符、Unicode字符

let character: Character = "a"
整数

不同进制的表示法

  • 二进制以0b开头
  • 八进制以0o开头
  • 十六进制以0x开头
let intDecimal = 17 // 十进制
let intBinary = 0b10001 // 二进制
let intOctal = 0o21 // 八进制
let intHexadecimal = 0x11 // 十六进制
浮点数
let doubleDecimal = 125.0 // 十进制
let doubleDecimal2 = 1.25e2 // 也是125.0的另一种写法,表示1.25乘以10的二次方

let doubleDecimal3 = 0.0125
let doubleDecimal4 = 1.25e-2 // 也是0.0125的另一种写法,表示1.25乘以10的负二次方

let doubleHexadecimal1 = 0xFp2 // 十六进制,意味着15*2^2(15乘以2的二次方),相当于十进制的60
let doubleHexadecimal2 = 0xFp-2 //十六进制,意味着15*2^-2(15乘以2的负二次方),相当于十进制的3.75

整数和浮点数可以添加额外的零或者下划线来增强可读性

let num = 10_0000
let price = 1_000.000_000_1
let decimal = 000123.456
数组
let array = [1, 2, 3, 4]
字典
let dictionary = ["age" : 18,
                  "height" : 1.75]

类型转换

整数转换

let int1: UInt16 = 2_000
let int2: UInt8 = 1
let int3 = int1 + UInt16(int2)

整数、浮点数转换

let int = 3
let double = 0.1415926
let pi = Double(int) + double
let intPi = Int(pi)

字面量可以直接相加,因为数字字面量本身没有明确的类型

let result = 3 + 0.14159

元组(tuple)

元组是可以多种数据类型组合在一起

let http404Error = (404, "Not Found")
print("The status code is \(http404Error.0)")

// 可以分别把元组里的两个值分别进行赋值
let (statusCode, statusMsg) = http404Error
print("The status code is \(statusCode)")

// 可以只给元组里的某一个值进行赋值
let (justTheStatusCode, _) = http404Error

// 可以在定义的时候给元组里面的值起名
let http200Status = (statusCode: 200, description: "ok")
print("The status code is \(http200Status.statusCode)")

流程控制

if-else

Swift里的if else后面的条件是可以省略小括号的,但大括号不可以省略

let age = 10

if age >= 22 {
    print("Get married")
} else if age >= 18 {
    print("Being a adult")
} else if age >= 7 {
    print("Go to school")
} else {
    print("Just a child")
}

if else后面的条件只能是Bool类型

-w718

while

var num = 5
while num > 0 {
	print("num is \(num)")
	// 打印了五次
}

repeat-while相当于C语言中的do-while

先执行一次,再判断条件循环

var num = -1
repeat {
	print("num is \(num)")
	// 打印了一次
} while num > 0

这里不用num--是因为Swift3开始,已经去掉了自增(++)、自减(--)运算符

for

1.闭区间运算符:a...b,相当于a <= 取值 <= b

// 第一种写法
let names = ["Anna", "Alex", "Brian", "Jack"]
for i in 0...3 {
    print(names[i])
}
// 第二种写法
let range = 0...3
for i in range {

}

// 第三种写法
let a = 1
let b = 3
for i in a...b {

}

循环里的i默认是let,如需要更改加上var

for var i in 0...3 {

}

不需要值的时候用_来表示

for _ in 0...3 {

}

2.半开区间运算符:a..<b,相当于a <= 取值 < b

for i in 0..<3 {

}

3.单侧区间:让一个区间朝一个方向尽可能的远

for i in ...3 {

}

for _ in 3... {

}

4.区间运算符还可以用在数组上

let names = ["Anna", "Alex", "Brian", "Jack"]

for name in names[0...3] {
    print(name)
}

for name in names[2...] {
    print(name)
}

for name in names[...2] {
    print(name)
}

for name in names[..<2] {
    print(name)
}

let range = ...5
range.contains(4)

5.区间的几种类型

闭区间 ClosedRange<Int> 
1...3

半开区间 Range<Int>
 1..<3
 
单侧区间 PartialRangeThrough<Int>
...3

6.字符、字符串也能使用区间运算符,但默认不能用在for-in

let stringRange1 = "cc"..."ff"
stringRange1.contains("cd")

let stringRange2 = "a"..."f"
stringRange2.contains("c")

let characterRange:ClosedRange<Character> = "\0"..."~"
characterRange.contains("G")

7.带间隔的区间值

let hours = 10
let hourInterval = 2

// tickmark的取值,从4开始,累加2,不超过10
for tickmark in stride(from: 4, through: hours, by: hourInterval) {
	print(tickmark)
	// 4,6,8,10
}

switch

使用同C语言的switch,不同的是case、default后面不写大括号{}

var number = 1

switch number {
case 1:
    print("number is 1")
    break
case 2:
    print("number is 2")
    break
default:
    print("number is other")
    break
}

默认不写break,并不会贯穿到后面的条件

var number = 1

switch number {
case 1:
    print("number is 1")
case 2:
    print("number is 2")
default:
    print("number is other")
}

使用fallthrough可以实现贯穿效果

var number = 1

switch number {
case 1:
    print("number is 1")
    fallthrough
case 2:
    print("number is 2")
default:
    print("number is other")
}

// 会同时打印number is 1,number is 2

switch必须要保证能处理所有情况

注意:像判断number的值,要考虑到所有整数的条件,如果不要判断全部情况,加上default就可以了

-w722

case、default后面至少要有一条语句

如果不想做任何事,加个break即可

var number = 1

switch number {
case 1:
    print("number is 1")
case 2:
    break
default:
    break
}

如果能保证已处理所有情况,也可以不必使用default

enum Answer { case right, wrong }

let answer = Answer.right

switch answer {
case .right:
    print("right")
case .wrong:
    print("wrong")
}

switch也支持CharacterString类型

let string = "Jack"

switch string {
case "Jack":
    fallthrough
case "Rose":
    print(string)
default:
    break
}

switch可以同时判断多个条件

let string = "Jack"

switch string {
case "Jack", "Rose":
    print(string)
default:
    break
}

let character: Character = "a"

switch character {
case "a", "A":
    print(character)
default:
    break
}

switch也支持区间匹配和元组匹配

let count = 62

switch count {
case 0:
    print("none")
case 1..<5:
    print("a few")
case 5..<12:
    print("several")
case 12..<100:
    print("dozens of")
default:
    print("many")
}

可以使用下划线忽略某个值

let point = (1, 1)
switch point: {
case (2, 2):
	print("1")
case (_, 0):
	print("2")
case (-2...2, 0...):
	print("3")
} 

值绑定,必要时let也可以改成var

let point = (2, 0)
switch point: {
case (let x, 0):
	print(x)
case (0, let y):
	print("2")
case let (x, y):
	print("3")
} 

where

一般where用来结合条件语句进行过滤

let point = (1, -1)
switch point {
case let (x, y) where x == y:
    print("on the line x == y")
case let (x, y) where x == -y:
    print("on the line x == -y")
case let (x, y):
    print("\(x), \(y) is just some arbitrary point")
}

for i in 0...5 where i == 3 {
    print(i)
}

标签语句

outer来标识循环跳出的条件

outer: for i in 1...4 {
	for k in 1...4 {
		if k == 3 {
			continue outer
		}
		
		if i == 3 {
			break outer
		}
	}
}
posted on 2021-03-08 13:56  FunkyRay  阅读(651)  评论(0编辑  收藏  举报