Swift-类和结构体(Class and Structures)
Posted 人散风中
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift-类和结构体(Class and Structures)相关的知识,希望对你有一定的参考价值。
前言
与其他编程语言不通,Swift并不要求我们为自定义的类和结构体去创建独立的接口和实现文件。我们所要做的就是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其他代码的外部接口。
小节包含内内容:
- 列表内容
- 类和结构体的对比
- 结构体和枚举是值类型
- 类是引用类型
- 类和结构体的选择
- 字符串、数组、字典类型的赋值与复制行为
分条详述
类和结构体对比
首先,Swift中类和结构体有很多共同点,共同之处在于(PS:关于属性、方法、下标脚本、构造过程、扩展和协议,其实后面都会说到,教材中提供了书中的具体位置链接):
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义附属脚本用于访问值
- 定义构造器用于生成初始值
- 定义扩展用以增加默认实现的功能
- 事先协议以提供某种标准功能
与结构体相比,类还有如下的附加功能(PS:关于继承、类型转换、析构过程和自动引用计数,都是后面要说的内容):
- 继承允许一个类继承另一个类的特征
- 类型转换允许运行时检查和解释一个类实例的类型
- 解构器允许一个类实例解释任何其被分配的资源
- 引用计数允许对一个类多次引用
结构体总是通过被复制的方式在代码中传递,不使用引用计数
类和结构体有着类似的定义方式。通过关键字class和struct来分别表示类和结构体,并在一对大括号内定义他们的具体内容:
class SomeClass // 类内部实现 struct SomeStructure // Structure definition goes here
每次定义一个新类,实际上都是定义了一个新的Swift类型,所以命名的时候注意规范,即命名时首字母大写,枚举也是如此。属性和方法名字首字母小写。命名时都要遵循驼峰命名法,并且起名字的时候尽量词能达意。
下面根据具体的例子来说明问题:// 结构体,描述一个显示器的分辨率 struct Resolution var width = 0 var height = 0 // 类,描述一个视频显示器的特定模式 class VideoMode var resolution = Resolution() var interfaced = false var frameRate = 0.0 var name: String?
结构体和类都可以通过构造器语法来创建实例进行使用,构造器语法最简单的就是在类或者结构体名称后面添加小括号,构造时属性均会被初始化默认值。如:
// 构造结构体和类的实例 let someResolution = Resolution() let someVideoMode = VideoMode()
可以通过点语法访问结构体或者类的属性或方法,并且当属性可变,即用var修饰时,可以改变属性值。相比于OC,Swift可以改变结构体或类的属性的子属性的值,而不需要为整个属性赋新值。
// 构造结构体和类的实例 var someResolution = Resolution() let someVideoMode = VideoMode() // 点语法访问属性并修改值 someResolution.height = 200 someVideoMode.frameRate = 12.12 someVideoMode.resolution.width = 300
注意,所有的结构体都有一个自动生成的成员逐一构造器,就是建立的时候为每个属性赋值。然而类并没有这个特性。只需在构造时输入左括号,自然会有提示。
结构体和枚举是值类型
值类型赋值给一个变量、常量或者被传递给一个函数时,其值会被拷贝,新拷贝的值和原来的值是完全隔离的,即他们的改变是独立的。在Swift中,整数、浮点数、布尔值、字符串、数组和字典,都是值类型,并且在底层都是以结构体的形式所实现。显然,结构体和枚举类型都是值类型。下面简单地代码很能说明问题:
// 值传递,对象以及所有属性都发生了拷贝 let someResolution = Resolution(width: 1920, height: 1080) var anotherResolution = someResolution anotherResolution.width = 2880 anotherResolution.height = 1600 // 通过输出结果,可以清晰体会到值传递是复制了另外一份数据 print(someResolution.height,someResolution.width) // 1080 1920 print(anotherResolution.height, anotherResolution.width) // 1600 2880
类是引用类型
与值类型不同,引用类型再被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝,因此引用是引的已存在的示例本身而不是拷贝。可以理解为多个指针指向同一个内存区域,任何一个指针对数据进行操作时,其他指针取到数据也是已经被修改的数据。如:
// 类是引用类型 let someVideoMode = VideoMode() someVideoMode.frameRate = 2.05 someVideoMode.resolution.height = 300 let anotherVideoMode = someVideoMode anotherVideoMode.frameRate = 99.99 anotherVideoMode.resolution.height = 2222 // 展示现在两个类属性的值 someVideoMode.frameRate // 99.9999 someVideoMode.resolution.height // 2222 anotherVideoMode.frameRate // 99.999 anotherVideoMode.resolution.height // 2222
观察上面代码会看到一个比较迷惑的地方,那就是已经使用 let 设置类实例,为什么还能修改它的值呢?如果结构体使用 let 修饰,是无法更改里面的值的。为什么呢?为什么呢??原因很简单,因为类是引用类型,也就是说 someVideoMode 和 anotherVideoMode 本身并没有存储值,改变的仅仅是被引用的属性的值,他们本身的值并没有改变,所以可以用 let 修饰为常量来使用。
因为类是引用类型,有可能多个常量和变量幕后同时引用一个类实例。如果能够判断两个常量或者变量是否引用同一个类实例,将会很有帮助。为了达到这种目的,Swift内建了两个恒等运算符:
- 等价于(===)
- 不等价于(!==)
注意,”等价于“(用三个等号表示 ===) 与 等于(用两个等号表示 ==)的不同:
- “等价于”表示两个类类型(class type)的常量或者变量引用同一个类类型。
- “等于”表示两个实例的值“相等”或“相同”,判断时要遵照设计者定义的评判标准,因此,相对于“相等”来说,这事一种更合适的叫法。
类和结构体的选择
当考虑使用结构体合适使用类的时候,如果能用结构体,就果断使用结构体吧,尽量少的使用类。我在看atSwift第一届Swift开发者大会的时候,有好几个演讲人员都强调了这一点,能用结构体就不用类。在教材中,也是提供了什么情况下使用结构体效果更好。
按照通用的准则,当符合一条或多条以下条件时,请考虑使用结构体:- 该数据结构主要目的是用来封装少量相关简书数据值。
- 有理由预计该数据结构的实例再被赋值或传递时,封装的数据将会被拷贝而不是被引用。
- 该数据结构图中存储的值类型属性,也应该被拷贝,而不是被引用。
- 该数据结构不需要去继承另一个既有类型的属性或者行为。
举例来说,一下情境中适合使用结构体:
- 几何形状的大小,封装一个width属性和一个height属性,两者均为Double类型。
- 一定范围内的路径,封装一个start属性和一个length属性,两者均为Int类型。
- 三维坐标系内一点,封装 x/y/z 属性,三者均为Double类型。
教程中的话:在所有其他案例中,定义一个类,生成它的实例,并通过引用来管理和传递。实际上,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。
其实,当教材和现实有了点冲突,我选择相信多用结构体。。。
关于Swift中的值传递和OC中的常用数据类型
在Swift中,所有值传递都是以拷贝的形式发生的,他们的低层都是由结构体实现的。这点和和OC中是不一样的。在Object-C中,NSString、NArray和NSDictionary中低层均以类的形式实现,它们在被赋值或者被传入参数时,不会发生值拷贝,而是传递现有实例的引用。
注意,以上对字符串、数组、字典的“拷贝”行为的描述,在代码中,好像拷贝行为看起来总会发生。然而,Swift在幕后只在绝对必要时才执行实际的拷贝。Swift管理所有值拷贝以确保性能最优化,所以没必要去回避赋值来保证性能最优化。
结束语
为啥现在写的这么慢了呢?是因为工作忙了么,毛线,就是过了新鲜劲,懒了。。。。。吾日三省吾身,早上吃什么,中午吃什么,晚上吃什么,就是忘了自省下为啥今天没坚持写点东西~
昨天晚上把权利的游戏第六季的前三集一次性看完了,也是过瘾,红巫女威武,囧哥威武!另外,感觉这张图的尺度好大~滑稽.jpg
另外,点击查看前几篇文章
以上是关于Swift-类和结构体(Class and Structures)的主要内容,如果未能解决你的问题,请参考以下文章