本想把枚举、结构体和类都一起放到上一篇《Swift 学习记:基础知识》之中,但是当把一些功能,如属性和方法都剥离到另一篇笔记之后,发现独立成一篇更方便理解,内容也更简约。

故。

枚举

枚举(enumeration)能让你定义明确类型的实例。

定义

使用 enum 关键字定义枚举:

enum TestEnum {
    case left
    case right
    case center
}

// 创建枚举实例
var testEnum: TestEnum = TestEnum.left // 显式声明类型
var testEnum = TestEnum.left // 或者使用类型推断创建
testEnum = .right // 重新赋值时可省略

注:第一次创建枚举的实例时必须指定枚举名

原始值

当需要存储或传输枚举时,可使用原始值(raw value)。

// 在枚举名后面加上希望的原始值类型
enum TestEnum: Int {
    case left
    case right
    case center
}

// 使用 .rawValue 查看原始值
print(TestEnum.right.rawValue) // 返回 1

注:整数原始值的默认值,从 0 开始;

指定原始值

enum TestEnum: Int {
    case left   = 10 
    case right // 如果不省略原始值,将根据上一位数字递增,这里为11
    case center = 30
}

// 依据原始值,获得枚举值
let enumVar = TestEnum(rawValue: 30) // 返回 center

字符串原始值

// 原始值类型为 String
enum testEnum: String {
    case left   = "zuo"
    case right // 省略原始值将使用原值,这里为 right
    case center = "zhong"
}

关联值

关联值(Associated Values)可以让你把数据附在枚举实例上,不同成员可以有不同类型的关联值。

enum ShapeEnum {
    // 关联值类型为 Double
    case square(side: Double)
    case rectangle(width: Double, height: Double)
    // 使用 switch 语句检查和计算
    func area() -> Double {
        switch self {
        case .square(let side):
            return side * side
        case .rectangle(let width, let height):
            return width * height
        }
    }
}

// 关联值
var shareShape = ShapeEnum.square(side: 10)

shareShape.area() // 将返回 100

注:

  • 关联值,即把参数附加到方法上;
  • 不是所有的枚举都需要关联值,两者可以混合;

递归枚举

递归枚举(Recursive Enumerations)是拥有另一个枚举作为枚举成员关联值的枚举,在声明枚举成员之前需要使用 indirect关键字来明确它是递归的.

enum Calc {
    case num(Int)
    indirect case add(Int, Calc)
}

// 也可以在枚举之前标记,而不是针对单个成员
indirect enum Calc {
    case num(Int)
    case add(Int, Calc)
}

结构体和类

结构体(Structure)和类(Classes)是构建应用这座大厦的支柱。

定义

关键字 struct 定义结构体,class 关键字定义类:

// 定义结构体并初始化
struct TestStruct {
    var width = 0
    var height = 0
}

// 定义类并初始化
class TestClass {
    var width = 0
    var height = 0
}

// 创建实例
let testClass = TestClass()

// 使用点语法赋予类新值
testClass.height = 7

// 使用点语法访问属性
print(testClass.height) // 返回 7

枚举、结构体和类的异同与选择

从功能上看三者之间的区别:

  • 相同点,均支持
    • 属性:存储值;
    • 方法:提供功能;
    • 下标:使用下标语法访问值;
    • 初始化:初始化状态;
    • 扩展:增加默认实现功能;
    • 协议:提供特定类型的标准功能;
  • 类独有
    • 继承:可以让一个类继承另一个类的特征;
    • 类型转换:运行检查和解释一个类实例的类型;
    • 反初始化:允许一个类实例释放任何被其所分配的资源;
    • 自动引用计数:允许对一个类实例进行多次引用;

但是结构体和类除了上面列出的功能之外,另外还有一个主要区别:枚举和结构体是值类型,而类是引用类型,值类型在产生操作时会产生一个副本,而引用类型,则是创建引用。或者说,值类型是拷贝(复制)操作,相互独立,不同步更改;而引用类型是替身(快捷方式),指向的是源文件,会同步更改。

struct TestStruct {
    var say = "Hello"
}

class TestClass {
    var say = "Hello"
}

var testStruct = TestStruct()
var str = testStruct
str.say = "Hi"
print(testStruct.sayi // 值类型,不会同步更改,所以返回 Hello

var testClass = TestClass()
var cla = testClass
cla.say = "Hi"
print(testClass.say) // 引用类型,同步更改,返回 Hi

选结构体还是类

从之前的简单示例可以看出,结构体和类的语法相似,功能相似,所以如何在两者之间选择:

  • 选结构体(值类型)
    • 需要传值;
    • 不需要继承;
    • 数据比较直观;
    • 明确知道数据需要被拷贝;
  • 选类(引用类型)
    • 其它情况

除非绝对清楚需要引用类型的好处,否则用结构体比较合适,值类型更容易理解,也无需担心实例发生变化。

注:枚举、结构体和类均使用大驼峰式命名法,方法和属性则使用小大驼峰式命名法

信息

版本

  • Xcode 10.1
  • Swift 4.2.1