基础大杂烩

上一篇:集合类型
当前篇:集基础大杂烩
下一篇:函数

元组

元组把多个值组合成一个复合值,元组中的值可以是任何类型,我们用元组来模拟一下人这种类型,我们把人的姓名、昵称、性别、籍贯、年龄等信息组合成一个复合类型

let jiangming = ("姜明", "小明", "男", "重庆", 24)
let myName = jiangming.0
let myHometown = jiangming.3

我们可以通过元素的位置下标来访问元组中的元素,这样使用起来意思不明,我们可以给元组的每一个元素起一个名字

let jiangming = (name: "姜明", nick: "小明", gender: "男", hometown: "重庆", age: 24)
let myName = jiangming.name
let myHometown = jiangming.hometown

如果我们自己定义元组的类型,不使用自动类型推断

let jiangming: (name: String, nick: String, gender: String, hometown: String, age: Int) = ("姜明", "小明", "男", "重庆", 24)
let myName = jiangming.name
let myHometown = jiangming.hometown

这样的类型定义写起来太麻烦,而且如果要在其他地方使用这个元组类型,又要写一遍很长的类型声明,我们可以给这样的类型起一个专用名字,于是就有了类型别名

类型别名

类型别名 typealias 就是给某个类型起一个别名,这样你就可以用自己喜欢或者更好理解的方式去使用类型名称,但是要注意在你的项目中类型名称包括别名是不能重复的,否则会编译失败

我们给上面的元组起一个别名

typealias Person = (name: String, nick: String, gender: String, hometown: String, age: Int)
//现在 Person 就代表我们自己定义的元组类型了
let jiangming: Person = ("姜明", "小明", "男", "重庆", 24)
let myName = jiangming.name
let myHometown = jiangming.hometown

我们可以给任意类型起别名

typealias 整数 = Int
let a: 整数 = 0

可选类型

上一节课我们提到了可选类型,任何类型都可以声明为可选的类型,方式就是 类型名? ,表示它的值可能是空的,也可能有值。比如,我可以用字符串来创建一个整数,但是像 “abc” 这样的字符串是不能转换成整数的,所以用字符串来创建整数得到的结果一定是一个 Int?

let aString = "abc"
let possibleNumber = Int(aString)
//possibleNumber 被推断为 Int? 类型,并且它的值为 nil
let aString = "123"
let possibleNumber = Int(aString)
//possibleNumber 被推断为 Int? 类型,并且它的值为 123

强制解析

当我们使用可选值的时候,可以在其名字后面加上 ! 来转换成普通值,这叫 强制解析 ,在进行强制解析的时候一定要确保可选值不为空,对一个空值进行强制解析会造成程序崩溃

let aString = "123"
let possibleNumber = Int(aString)
if possibleNumber != nil {
    //如果判断为有值,则用!进行强制解析
    print(possibleNumber!)
} else {
    print("This is not a string that can be resolved as a number")
}

强制解析实际上就是把可选类型的值强制转换成非可选类型的值,所以需要确保其是有值的

let aString = "123"
let possibleNumber = Int(aString)
if possibleNumber != nil {
    let definiteNumber: Int = possibleNumber!
    print(definiteNumber)
} else {
    print("This is not a string that can be resolved as a number")
}

隐式解析

可选类型还有另一种定义方法,那就是 类型名! ,仅仅是问号和感叹号的区别,这两种方式定义的类型都是可选类型,但是用叹号定义的可选类型已经包含了解析的语义,我们不用在使用的过程中进行强制解析,只需要判断是否为空就行了

let possibleNumber: Int!
possibleNumber = Int("123")
if possibleNumber != nil {
    print(possibleNumber)
}

隐式解析可选类型只做了解,在遇到的时候知道这个概念就行了,实际上隐式解析的区别就是,只需要做非空判断,不需要强制解析

空值替换

let aString = "abc"
let possibleNumber = Int(aString)
let replacedNumber: Int = possibleNumber ?? 0

双问号 ?? 的意思是如果有值,就取其值,如果没有值,就取后面给定的默认值,如果默认值是普通类型,那自然得到的结果就是一个非可选类型了

可选绑定

试想一下这样的情况,有一个可选值,而后面有很多行代码都要用到这个值,你就需要在每个地方都用一次感叹号来强制解析,就像下面这样

let aString = "123"
let possibleNumber = Int(aString)
if possibleNumber != nil {
    print(possibleNumber!)
    print(possibleNumber!)
    print(possibleNumber!)
    print(possibleNumber!)
    print(possibleNumber!)
    print(possibleNumber!)
} else {
    print("This is not a string that can be resolved as a number")
}

这样写比较难看,而且强制解析多多少少也是需要计算的,我们可以像下面这样只解析一次

let aString = "123"
let possibleNumber = Int(aString)
if possibleNumber != nil {
    let definiteNumber: Int = possibleNumber!
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
} else {
    print("This is not a string that can be resolved as a number")
}

Swift 为我们提供了一种更优雅的写法叫 可选绑定 ,可选绑定其实就是把上面的判断以及强制解析两个过程合成一句话

let aString = "123"
let possibleNumber = Int(aString)
if let definiteNumber = possibleNumber {
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
    print(definiteNumber)
} else {
    print("This is not a string that can be resolved as a number")
}

可选绑定可以有多个语句,用逗号隔开

let string1 = "123"
let possibleNumber1 = Int(string1)
let string2 = "abc"
let possibleNumber2 = Int(string2)
if let definiteNumber1 = possibleNumber1, let definiteNumber2 = possibleNumber2 {
    //需要两个条件都成立才算成功
    print(definiteNumber1)
    print(definiteNumber2)
} else {
    print("There is at least one string that can be resolved as a number")
}

枚举

枚举是编程语言中一个非常常用的概念,比如说 方向 这个类型,它总共就四种取值,而且四种取值只能取其一(咱先不考虑西北东北这种方向,假设就四种方向),这种类型我们就用枚举来表示

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

let myWayForward = Position.north  

enum 表示定义一个枚举类型,Position 是我们自己定义的枚举类型的名字,大括号括起来的就是我们自己定义的枚举类型的具体定义,我们给 Position 类型定义了四个值:north,south,east,west ,实际上,这个类型是我们自己定义的第一个类型,今后很多的类型都会是我们自己定义的

我们用了一个字面量来初始化一个枚举值 myWayForward ,方式就是 枚举类型名.其中的某个值 ,现在 myWayForward 就是一个 Position 类型的值,它的值等于 north ,当一个枚举的类型已知的时候,我们可以把枚举类型名称省略掉,只留下一个小点就行了

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

let myWayForward: Position = .north

枚举判断

我们可以用 if 来判断枚举值

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

let myWayForward: Position = .north
if myWayForward == .north {
    print("一路向北")
} else if myWayForward == .south {
    print("一直往南方开")
} else if myWayForward == .east {
    print("东方之珠")
} else {
    print("一路向西")
}

而最常用的是用 switch-case 语句来处理枚举值

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

var myWayForward: Position = .north
myWayForward = .south
switch myWayForward {
case .north:
    print("一路向北")
case .south:
    print("一直往南方开")
case .east:
    print("东方之珠")
case .west:
    print("一路向西")
//当所有可能的结果都被列举了,default 就不需要了
}

枚举原始值

枚举中的值可以关联一个原始值,可以是整数,浮点数,字符串或者字符

enum Position: Int {
    case north = 0
    case south = 1
    case east = 2
    case west = 3
}

var myWayForward: Position = .north
myWayForward = .south
print(myWayForward.rawValue)
//通过 rawValue 属性获取枚举值的关联值

如果我们定义的枚举值需要跟其他应用通信,需要是关联整数的枚举值,因为通信需要标准统一,不能我用字符串别人用整数,如果仅仅是本地使用,而且不需要关联任何原值值,可以不关联

在通信过程中,我们通过网络获取到的枚举数据一般都是一个整数值,需要使用整数值来创建关联整数类型的枚举

enum Position: Int {
    case north = 0
    case south = 1
    case east = 2
    case west = 3
}

var myWayForward: Position? = Position(rawValue: 0)
myWayForward = .south
print(myWayForward!.rawValue)

这种方式创建的枚举值是可选类型枚举值,因为我们给定的原始值不一定会有对应的枚举值,代码中我没有做非空判断是因为我知道 0 对应了 north

当我们用整数作为枚举的关联值,可以不必为每一个枚举值都指定关联值,Swift 会为我们自动推断,我们只需要指定第一个枚举值的原始值,后面的枚举值的原始值单调递增1

enum Position: Int {
    case north    //0,0 开头的情况可以省略不写
    case south    //1
    case east     //2
    case west     //3
}
enum Position: Int {
    case north = 1
    case south    //2
    case east     //3
    case west     //4
}

用字符串作为关联值有时候会非常方便,请看下面两种代码

enum Mood {
    case happy 
    case anger 
    case sad 
    case surprised 
}

let myMood = Mood.happy
switch myMood {
case .happy:
    print("")
case .anger:
    print("Get out of my face!")
case .sad:
    print("Leave me alone please!")
case .surprised:
    print("Hahahahahaha!!")
}
enum Mood: String {
    case happy = ""
    case anger = "Get out of my face!"
    case sad = "Leave me alone please!"
    case surprised = "Hahahahahaha!"
}

let myMood = Mood.happy
print(myMood.rawValue)
//直接就输出了关联的字符串,不需要做判断

上一篇:集合类型
当前篇:集基础大杂烩
下一篇:函数

你可能感兴趣的:(基础大杂烩)