ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
类和结构体是⼈们构建代码所⽤的⼀种通⽤且灵活的构造体。我们可以使⽤完全相同的语法规则来为类和结构体定义属性(常量、变量)和添加⽅法,从⽽扩展类和结构体的功能。 与其他编程语⾔所不同的是,Swift 并不要求你为⾃定义类和结构去创建独⽴的接⼝和实现⽂件。你所要做的是在⼀个单⼀⽂件中定义⼀个类或者结构体,系统将会⾃动⽣成⾯向其它代码的外部接⼝。 ## 一、类和结构体的对比 1、Swift 中类和结构体有很多共同点。共同处在于: (1)定义属性⽤于存储值 (2)定义⽅法⽤于提供功能 (3)定义附属脚本⽤于访问值 (4)定义构造器⽤于⽣成初始化值 (5)通过扩展以增加默认实现的功能 (6)实现协议以提供某种标准功能 与结构体相⽐,类还有如下的附加功能: (1)继承允许⼀个类继承另⼀个类的特征 (2)类型转换允许在运⾏时检查和解释⼀个类实例的类型 (3)解构器允许⼀个类实例释放任何其所被分配的资源 (4)引⽤计数允许对⼀个类的多次引⽤ 注意: 结构体总是通过被复制的⽅式在代码中传递,因此请不要使⽤引⽤计数。 2、定义: 类使用关键字class,结构体使用关键字struct ~~~ class SomeClass { // class definition goes here } struct SomeStructure { // structure definition goes here } ~~~ 注意: 在你每次定义⼀个新类或者结构体的时候,实际上你是有效地定义了⼀个新的 Swift 类型。因此请使⽤  UpperCamelCase  这种⽅式来命名(如  SomeClass和 SomeStructure  等),以便符合标准Swift 类型的⼤写命名⻛格(如 String  , Int  和 Bool  )。相反的,请使⽤ lowerCamelCase  这种⽅式为属性和⽅法命名(如 framerate  和 incrementCount  ),以便和类区分。 这是官方建议,但如果你非要用小写,属性和方法非要用大写,那也不会出错 下面定义一个类和一个结构体: ~~~ class PersonClass { var name : String = "" var age : Int = 0 var sex : String? } struct Dog { var master = PersonClass() var dogName = "" } ~~~ 除了关键字不一样,看不出什么区别的 3、类和结构体实例(通常类的实例叫做类对象) 类PersonClass是描述一类人的共同属性,并没有具体到哪个人,所以需要一个实例来具体描述某一个人,结构体也是一样,下面是生成实例的语法: ~~~ class PersonClass { var name : String = "" var age : Int = 0 var sex : String? } struct Dog { var master = PersonClass() var dogName = "" } let onePerson = PersonClass() let oneDog = Dog() ~~~ 4、属性访问: 通过使⽤点语法(dot syntax),可以访问实例中所含有的属性。其语法规则是,实例名后⾯紧跟属性名,两者通过点号(.)连接 ~~~ struct Mouse { var brand = "apple" var price = 999.0 } class Computer { var mouse = Mouse() var display = "dell" var keyboard = "lenovo" var mainframe = "asus" var price = 9999.0 } var oneMouse = Mouse() var oneComputer = Computer() print("the mouse brand is \(oneMouse.brand), the computer display is \(oneComputer.display)") print("the mouse's price of the computer is \(oneComputer.mouse.price)") oneComputer.mouse.price = 888.0 print("the mouse's price of the computer is \(oneComputer.mouse.price)") //注意: 与 Objective-C 语⾔不同的是,Swift 允许直接设置结构体属性的⼦属性。 //上⾯的最后⼀个例⼦,就是直接设置了 oneComputer 中 oneMouse 属性的 price 这个 //⼦属性,以上操作并不需要重新设置 oneMouse 属性。 //the mouse brand is apple, the computer display is dell //the mouse's price of the computer is 999.0 //the mouse's price of the computer is 888.0 ~~~ 5、结构体类型的成员逐⼀构造器 所有结构体都有⼀个⾃动⽣成的成员逐⼀构造器,⽤于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐⼀构造器之中: ~~~ var twoMouse = Mouse(brand: "lenovo", price: 500.0) print("the mouse's brand is \(twoMouse.brand), and the price is \(twoMouse.price)") //the mouse's brand is lenovo, and the price is 500.0 ~~~ 与结构体不同,类实例没有默认的成员逐⼀构造器 ## 二、结构体和枚举是值类型 值类型被赋予给⼀个变量、常量或者本⾝被传递给⼀个函数的时候,实际上操作的是其值的拷⻉ 在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Boolean)、字符串(string)、数组(array)和字典(dictionary),都是值类型,并且都是以结构体的形式在后台所实现 在 Swift 中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制 ~~~ var twoMouse = Mouse(brand: "lenovo", price: 500.0) print("the mouse's brand is \(twoMouse.brand), and the price is \(twoMouse.price)") //the mouse's brand is lenovo, and the price is 500.0 var threeMouse = twoMouse threeMouse.price = 555.0 print("twoMouse price is \(twoMouse.price)") print("threeMouse price is \(threeMouse.price)") //twoMouse price is 500.0 //threeMouse price is 555.0 ~~~ 上面例子中,将twoMouse赋给threeMouse,其实就是讲twoMouse拷贝一份给threeMouse,修改threeMouse中的值,twoMouse中的值并不受影响 ## 三、类是引用类型 ~~~ var computer1 = Computer() print("the computer1's price is \(computer1.price)") var computer2 = computer1 computer2.price = 1000000.0 print("the computer2's price is \(computer2.price)") print("the computer1's price is \(computer1.price)") //the computer1's price is 9999.0 //the computer2's price is 1000000.0 //the computer1's price is 1000000.0 ~~~ 与值类型不同,引⽤类型在被赋予到⼀个变量、常量或者被传递到⼀个函数时,操作的是引⽤,其并不是拷⻉。因此,引⽤的是已存在的实例本⾝⽽不是其拷⻉,所以上面操作computer2的price属性时,computer1的price属性值也改变了,其实computer1和computer2指向同一个对象,它们操纵的也是同一个对象,这就是引用 值类型和引用类型分析如下: ![](https://box.kancloud.cn/2016-05-05_572b1a034d5df.jpg) 1、恒等运算符 因为类是引⽤类型,有可能有多个常量和变量在后台同时引⽤某⼀个类实例。(对于结构体和枚举来说,这并不成⽴。因为它们作为值类型,在被赋予到常量、变量或者传递到函数时,其值总是会被拷⻉。) 如果能够判定两个常量或者变量是否引⽤同⼀个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符: 等价于 ( === ) 不等价于 ( !== ) 请注意 “等价于"  (⽤三个等号表⽰,===) 与 “等于"  (⽤两个等号表⽰,==)的不同:    “等价于”表⽰两个类类型(class type)的常量或者变量引⽤同⼀个类实例。    “等于”表⽰两个实例的值“相等”或“相同”,判定时要遵照类设计者定义定义的评判标准,因此相⽐于“相等”,这是⼀种更加合适的叫法。 ~~~ if computer1 === computer2 { print("computer1 等价于 computer2") } else { print("computer1 不等价于 computer2") } //computer1 等价于 computer2 ~~~ 2、指针 在 C,C++ 或者 Objective-C 语⾔中,使⽤指针来引⽤内存中的地址。⼀个 Swift 常量或者变量引⽤⼀个引⽤类型的实例与 C 语⾔中的指针类似,不同的是并不直接指向内存中的某个地址,⽽且也不要求你使⽤星号(*)来表明你在创建⼀个引⽤。Swift 中这些引⽤与其它的常量或变量的定义⽅式相同。 四、类和结构体的选择 什么时候使用类,什么时候使用结构体呢? 按照通⽤的准则,当符合⼀条或多条以下条件时,请考虑构建结构体: 结构体的主要⺫的是⽤来封装少量相关简单数据值。 有理由预计⼀个结构体实例在赋值或传递时,封装的数据将会被拷⻉⽽不是被引⽤。 任何在结构体中储存的值类型属性,也将会被拷⻉,⽽不是被引⽤。 结构体不需要去继承另⼀个已存在类型的属性或者⾏为 五、字符串(String)、数组(Array)、和字典(Dictionary)类型的赋值与复制 Swift 中 字符串(String)  , 数组(Array)  和 字典(Dictionary)  类型均以结构体的形式实现。这意味着String,Array,Dictionary类型数据被赋值给新的常量或变量,或者被传⼊函数或⽅法中时,它们的值会发⽣拷⻉⾏为(值传递⽅式) Objective-C中 字符串(NSString)  , 数组(NSArray)  和 字典(NSDictionary)  类型均以类的形式实现,这与Swfit中以值传递⽅式是不同的。NSString,NSArray,NSDictionary在发⽣赋值或者传⼊函数(或⽅法)时,不会发⽣值拷⻉,⽽是传递已存在实例的引⽤ 其实说白了,只要理解了什么是值类型,什么是引用类型,上面这些都很好理解。