swift5-语法篇

393 阅读7分钟

swift介绍

swift是2014年推出的开发语言,中文名称为雨燕。

版本

从1.X升级到5.X。

其中1,2, 3之间的版本不兼容。

编译过程

  • 导出抽象语法树swiftc -dump-ast main.swift -o main.ast
  • 生成sil代码swiftc -emit-sil main.swift -o main.sil
  • 生成llvm ir代码swiftc -emit-ir main.swift -o main.ir
  • 生成汇编可执行文件swiftc -emit-assembly main.swift -o main

hello world

使用print进行字符串输出,其中Foundation可以不需要导入。

//import Foundation

print("Hello, World!")

变量和常量

变量使用var关键字,常量使用let关键字。 其中变量可以被多次修改,常量无法被修改。

var a = 10
a = 20
a = 30
let c = 40
//c = 50
print(a)
print(c)
var a = 10
a += 10
// 常量不要求在编译期确定值,只要求在使用之前赋值一次
let b = a
print(a)

格式化输出

print("a is \(a) c is \(c)")

playground

其中UIKit是UI控件,PlaygroundSupport则是让可以在Playground中查看到UI。

import UIKit
import PlaygroundSupport
let view = UIView()
view.frame = CGRect(x:0, y:0, width:100, height:100)
view.backgroundColor = UIColor.red
PlaygroundPage.current.liveView = view

一个playground可以新建多个page。

数据类型

  • 值类型
    • 枚举
    • 结构体 Bool Int String Set Array Dictionay
  • 引用类型
    • class

整数类型Int, Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64。在32位平台Int是Int32,在64位平台Int是Int64。

// 根据数据类型,可以求最大值最小值。
print(Int.max)
print(Int.min)

// 十进制
var a = 10
// 二进制0b
var b = 0b100
// 八进制0o
var c = 0o10
// 十六进制0x
let d = 0x22

浮点数

// 默认都是double类型
var a = 10.0
// 等价于13.2 * 10的2次方 1320
var b = 13.2e2
// 等价于20.1 * 10的-2次方 0.201
var c = 20.1e-2
// 等价于0xF3 * 2的3次方 1944
var d = 0xF3p3
// 等价于0xF3 * 2的-3次方
var e = 0xF3p-3 30.375

bool类型只能是true或者false。let v = true

字符和字符串都是双引号,默认是字符串。如果要声明为字符类型,则必须强制添加类型声明。

let a = "h"
let b:Character = "h"
print(type(of: a))
print(type(of: b))

字符串

Swift中的字符串是字符组成,有些字符是由2个Unicode组成。也认为是一个字符。

import UIKit
var s1 = "\u{00E9}"
var s2 = "e\u{0301}"

// 字符数量一样多
print("\(s1) \(s1.count)")//é 1
print("\(s2) \(s2.count)")//é 1

print("\(s1.utf16.count)") //转成Unicode计数。只有1个
print("\(s2.utf16.count)") // 转成Unicode计数,有2个

print((s1 as NSString).isEqual(to: s2))//false

数组

var a = [10, 20.0, 30]
print(a)

字典

定义字典

// 自动推断类型, 只能是相同的类型,下面代码编译失败
//var dict1 = ["name":"小王", "age": 18]

var dict2 = ["name":"李白", "job":"打野"]

//print(type(of: dict1))
print(type(of: dict2))//Dictionary<String, String>

// 如果字典的类型不一致,可以手动指定类型
var dict3:[String: Any] = ["name":"小王", "age": 18]
print(type(of: dict3))//Dictionary<String, Any>

// 使用泛型指定数据类型
var dict4:Dictionary<String, String> = ["name":"鲁班七号", "JOB":"ADC"]
print(type(of: dict4))//Dictionary<String, String>

空字典

// 语法错误,无法确定类型
//var dict = [:]
//print(dict)

// 确定了数据类型,因此可以编译通过
var dict1:[Int: String] = [:]

// 使用泛型指定数据类型
var dict2:Dictionary<String, String> = [:]

// 类型+括号
var dict3 = [Int: Int]()
print(type(of: dict3)) // Dictionary<Int, Int>

字典方法

var dict1 = ["name":"小明", "addr":"china"]

// 有几个key
print(dict1.count) //2

// 是否是空的
print(dict1.isEmpty) //false

// 取值返回的option类型,返回对应的值或者nil
print(dict1["age"]) // nil

print(dict1["name"]) //Optional("小明")

// 对于确定有值,又不想被Optional包装,则可以使用!标识强制解包。如果没有值,强制解包会报错
print(dict1["name"]!) //小明


var dict2 = ["addr":"china", "name":"小明"]

// 判断2个字典是否相等
print(dict1 == dict2) // true

字典的遍历

var dict = ["name":"小明", "addr":"China"]

for v in dict{
    print(v)
}

/*
 (key: "addr", value: "China")
 (key: "name", value: "小明")
 */

for v in dict{
    print("key is \(v.key) value is \(v.value)")
}
/*
 key is addr value is China
 key is name value is 小明
 */

for (k, v) in dict {
    print("key is \(k) value is \(v)")
}
/*
 key is addr value is China
 key is name value is 小明
 */

字典的修改


var user = ["name":"age"]
print(user)//["name": "age"]

// 如果对应的key不存在,则新增一个键值对
user["addr"] = "china"
print(user)//["addr": "china", "name": "age"]

// 如果对应的key存在,则修改一个键值对
user["addr"] = "Beijing"
print(user)//["addr": "Beijing", "name": "age"]

// 设置对应的key的值为nil,则删除对应的键值对
user["addr"] = nil
print(user)//["addr": "Beijing", "name": "age"]

// key不存在,则新增
user.updateValue("China", forKey: "addr")
print(user)//["name": "age", "addr": "China"]

// key存在,则修改
user.updateValue("Beijign", forKey: "addr")
print(user)

// 删除,不能设置nil,得使用remove
//user.updateValue(nil, forKey: "addr")
user.removeValue(forKey: "addr")
print(user)// ["name": "age"]

// 清空数据
user.removeAll()
print(user) // [:]

类型转换

var a:Int8 = 10
var b: Int32 = 20
// 语法错误,数据类型不一致,不能直接运算
//var c = a + b

// 必须数据类型一致,才可以进行运算
var c = a  + Int8(b)
print(c)

元组

可以保存多个不同类型的数据。

var a = ("xiaoming", 18, "china")
print(a.0)
print(a.1)
print(a.2)

// 可读性更强
var b = (code:200, msg:"你好")
print(b.code)

流程控制语句

let a = 20
//if (a > 20){
// swift的括号可以省略
if a > 20{
    print("a > 20")
}else{
    print("a <= 20")
}
var b = 0
var sum = 0
while b < 101 {
    sum += b
    b += 1
}
print(sum)
var c = 0
var sum1 = 0
repeat {
    sum1 += c
    c+=1
}while c < 101
print(sum1)
let names = ["libai", "ake", "houzi"]
for i in 0...2{
    print(i)
    print(names[i])
}


// 默认for的变量是不可以修改的, 如果需要修改添加var修饰
for var i in 1...2 {

    i *= 2
    print(i)
}

// 如果不关心每次循环的值,可以使用下划线,
// for i in 0...9 ,如果声明了i但是不实用,则会警告
for _ in 0...9 {
    print("hello world")
}

// 半开区间 1<=i<5
for i in 1..<5 {
    print(i)
}

// for与数组
// ArraySlice<String> 返回的是数组切片
// names[2...] 如果不写后面的,表示一致到数组的最后一个元素
// names[...2] 表示从头开始
// names[..<2] 从头开始,不包含2
print(type(of: names[0...2]))
for name in names[0...2]{
    print(name)
}


// 带间隔的区间
for v in stride(from: 0, through: 10, by: 2) {
    print(v, terminator: " ")
}
// 0 2 4 6 8 10

// switch
// case和default后面不能有大括号
// switch必须处理所有情况。如果有default则自动包含了所有情况。
// case和default至少有一条语句,如果不需要执行代码,可以直接break
var numer = 1
switch numer {
case 1:
    print("1")
//    break //默认是break
    fallthrough // 会直接执行下一条case
case 2:
    print(2)
//    break
default:
    print("not match")
    break
}

// 区间匹配
let count = 10
switch count {
case 0:
    print("a is 0")
case 1...100:
    print("1 <= count <= 100")
default:
    break
}
// 元组匹配
var t1 = (100, 200)
switch t1 {
case (10, 20):
    print("(10, 20)")
case (_, 100):
    print("第二个值是100")
case (100, _):
    print("第一个值是100")
case (-100...100, 100...1000):
    print("好大一个数")
default:
    print("not match")
}

// 值匹配
var point = (10, 200)
switch point {
case (let x, 0): // 第二个必须是0才能匹配
    print("x is \(x)")
case (0 ,let y):
    print("y is \(y)")
case let (x, y):
    print(" x is \(x) y is \(y)")
}

// where
for v in 0...100 where v % 30 == 0 {
    print(v, terminator: " ")
    // 0 30 60 90
}
// 标签语句
outer: for i in 1...4 {
    for k in 1...4 {
        if k == 3 {
            continue outer
        }
        if i == 3 {
            break outer
        }
    }
}

函数

无参无返回值函数


func hello(){
    print("hello world")
}
hello()

如果函数没有返回值,也可以写成返回Void,空元组。

// 返回值是空可以返回Void
func test1() -> Void {

}
// 返回值是空可以返回空元组
func test2() -> () {

}
// 返回值是空可以不写返回值
func test3() {

}

有参数无返回值函数

func hello(name: String){
    print("你好 \(name)")
}
hello(name: "大哥")

可以传递多个参数

func add(num1:Int, num2: Int, num3: Int){
    var total = num1 + num2 + num3;
    print("total is \(total)")
}
add(num1: 10, num2: 20, num3: 30)

可以传递数组作为参数

func add1(a:[Int]){
    print(a)
}
func add2(a:Array<Int>){
    print(a)
}

add1(a: [1,2,3])
add1(a: [4,5,6])

可以传递字典作为参数

func hello1(data:[Int: Int]){
    print(data)
}

func hello2(data:Dictionary<Int, Int>){
    print(data)
}

var dict = [1:100, 2:89, 3: 78]

hello1(data: dict)
hello2(data: dict)

指针参数

基本数据类型,默认是值传递。无法修改原来的值。使用指针则传递的是引用。

func myadd(a: inout Int){
    a += 1
}

var a = 10;
myadd(a: &a)
print(a)

++=

具体的作用全部是由开发者去实现。

class Student{
    var age : Int = 10;
    static func +(stu:Student, stu2:Student){
        stu.age += stu2.age
    }
    
    static func +=(stu:Student, stu2:Student){
        stu.age = stu2.age
    }
}

var s = Student()
var s2 = Student()

s + s2
print(s.age) //20

s += s2
print(s.age) // 10

有参数有返回值

func hello(name: String) -> String{
    return "你好 \(name)"
}
var s = hello(name: "小明")
print(s)

如果函数体只有一句代码,可以省略return

func hello(name: String) -> String{
// 语法错误,不能有多行代码
//    var s = "你好 \(name)"
//    s
    "你好 \(name)"
}
var s = hello(name: "小明")
print(s)

// 返回元组
func matchMaxMin(a: Int, b: Int) -> (max: Int, min: Int) {
    if a > b {
        return (a , b)
    }else {
        return (b , a)
    }
}

print(matchMaxMin(a: 10,b: 20))
print(matchMaxMin(a: 100,b: 20).max)

函数的文档注释

/// 求2个整数的和
///
/// 求2个数的和,并返回和
///
/// - Parameter a: 第一个整数
/// - Parameter b: 第二个整数
/// - Returns: 返回值是整数
///
///  Note: 两个参数的类型都是整数,返回值也是整数
///
func sum(a: Int , b: Int) -> Int {
    a + b
}

截屏2022-07-17 10.55.51.png

参数标签

// 参数标签
func sum(first a: Int , second b: Int) -> Int {
    a + b
}

// 函数调用的时候可以使用参数标签的字段
print(sum(first: 10, second: 20))

// 省略参数标签使用下划线
func sum1(_ a: Int , _ b:Int ) -> Int {
    a + b
}
// 参数可以不写,直接写内容
print(sum1(10, 20))

函数参数可以提供默认值

// 默认值

func greet(name: String, text: String = "你好") {
    print("\(text) \(name)")
}
greet(name: "李白")
greet(name: "猴子", text: "welcome")

可变参数: 一个函数只能有一个可变参数,另外,可变参数后面的第一个参数不能使用省略标签func sum(a:Int ... , _ b: Int = 10)sum(10, 20)这样容易引起歧义,其中20是a还是b不好界定,所以不可以这样写。

// 可变参数

func all_print(a: Int...) {
    for v in a {
        print(v, terminator: " ")
    }
    // 100 200 300
}
all_print(a: 100, 200 ,300)

函数重载

  • 必须满足函数名称相同
  • 满足其一
    • 参数个数不同
    • 参数类型不同
    • 参数标签不同
func sum(a: Int, b: Int){
    print(a + b)
}
// 参数个数不同
func sum(a: Int, b: Int, c: Int){
    print(a + b + c)
}
//参数的类型不同
func sum(a: Int, b: Double) {
    print(Double(a) + b)
}
//标签不同
func sum(first a: Int ,second b : Int) {
    print(a + b)
}

// 形参不同
func sum(a1: Int , b : Int) {
    print(a1 + b)
}

类和对象

类使用class关键字。

class Person{
    var name:String
    var age:Int
    init(name:String, age:Int){
        self.name = name;
        self.age = age;
    }
}

var p = Person(name: "程咬金", age: 20);
print(p.name)
print(p.age)

多线程

Swift的多线程和OC基本一致。另外,Swift开始支持async,await。