Swift学习笔记(11)--类与结构体
类与结构是编程人员在代码中会经常用到的代码块。在类与结构中可以像定义常量,变量和函数一样,定义相关的属性和方法以此来实现各种功能。
和其它的编程语言不太相同的是,Swift不需要单独创建接口或者实现文件来使用类或者结构。Swift中的类或者结构可以在单文件中直接定义,一旦定义完成后,就能够被直接其它代码使用。
注意:一个类的实例一般被视作一个对象,但是在Swift中,类与结构更像是一个函数方法,在后续的章节中更多地是讲述类和结构的功能性。
1、类和结构的异同
类和结构有一些相似的地方,它们都可以:
定义一些可以赋值的属性;
定义具有功能性的方法
定义下标,使用下标语法
定义初始化方法来设置初始状态
在原实现方法上的可扩展性
根据协议提供某一特定类别的基本功能
更多内容可以阅读:属性,方法,下标,初始化,扩展和协议等章节
类还有一些结构不具备的特性:
类的继承性
对类实例实时的类型转换
析构一个类的实例使之释放空间
引用计数,一个类实例可以有多个引用
更多内容可以阅读:继承,类型转换,初始化自动引用计数
注意:结构每次在代码中传递时都是复制了一整个,所以不要使用引用计数
定义语法
类和结构拥有相似的定义语法,使用class关键词定义一个类,struct关键词定义结构。每个定义都由一对大括号包含:
class SomeClass { // class definition goes here } struct SomeStructure { // structure definition goes here }
注意:在定义类和结构时,一般使用UpperCamelCase命名法来定义类和结构的名称,比如SomeClass和SomeStructure,这样也符合Swift其它类型的标准。而给属性和方法命名时,一般时候lowerCamelCase命名法,比如frameRate和incrementCount等。
下面是一个结构和一个类的定义示例:
struct Resolution { var width = 0 var height = 0 } class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
上面的例子首先定义了一个叫Resolution的结构,用来描述一个像素显示的分辨率,它有两个属性分别叫width和height。这两个属性被默认定义为Int类型,初始化为0.
之后定义了一个叫VideoMode的类,为视频显示的显示方式。这个类有四个属性,第一个属性resolution本身又是一个结构,然后是另外两个属性。最后一个属性用到了可选字符串类型String?,表示这个属性可以存在,或者不存在为nil。
类和结构的实例
上面的两个定义仅仅是定义了结构Resolution和类VideoMode的整体样式,它们本身不是一个特定的分辨率或者显示方式,这时候就需要实例化这个结构和类。
实例化的语法相似:
let someResolution = Resolution() let someVideoMode = VideoMode()
类和结构都使用实例语法来完成实例化。最简单的实例语法就是用两个括号()完成。在这种情况下定义的实例中的属性都会完成默认初始化。更多内容可以参考初始化一章。
访问属性
使用.语法就可以方便地访问一个实例的属性。在.语法中,在实例名之后加上(.)再加上属性名即可,不需要空格:
println("The width of someResolution is \(someResolution.width)") // prints "The width of someResolution is 0"
在这个例子中,someResolution.width表示someResolution的width属性,返回了它的初始值0
也可以使用.语法连续地获取属性的属性,比如VideoMode中resolution属性的width属性
println("The width of someVideoMode is \(someVideoMode.resolution.width)") // prints "The width of someVideoMode is 0"
使用这种方法不仅可以访问,也可以赋值:
someVideoMode.resolution.width = 1280 println("The width of someVideoMode is now \(someVideoMode.resolution.width)") // prints "The width of someVideoMode is now 1280"
注意:和Objective-C不同,Swift能够直接设置一个结构属性的子属性,就像上面这个例子一样。
结构类型的成员初始化方法
每个结构都有一个成员初始化方法,可以在初始化的时候通过使用属性名称来指定每一个属性的初始值:
let vga = Resolution(width: 640, height: 480)
但是和结构不同,类实例不能够使用成员初始化方法,在初始化一章有专门的介绍。
2、结构和枚举类型是数值类型
数值类型是说当它被赋值给一个常量或者变量,或者作为参数传递给函数时,是完整地复制了一个新的数值,而不是仅仅改变了引用对象。
事实上读到这里你已经在前面几章见过数值类型了,所有Swift中的基础类型-整型,浮点型,布尔类型,字符串,数组和字典都是数值类型。它们也都是由结构来实现的。
在Swift中所有的结构和枚举类型都是数值类型。这意味这你实例化的每个结构和枚举,其包含的所有属性,都会在代码中传递的时候被完整复制。
下面的这个例子可以说明这个特性:
let hd = Resolution(width: 1920, height: 1080) var cinema = hd
声明了一个常量hd,是Resolution的实例化,宽度是1920,高度是1080,然后声明了一个变量cinema,和hd相同。这个时候表明,cinema和hd是两个实例,虽然他们的宽度都是1920,高度都是1080。
如果把cinema的宽度更改为2048,hd的宽度不会变化,依然是1920
cinema.width = 2048
println("cinema is now \(cinema.width) pixels wide") // prints "cinema is now 2048 pixels wide"
println("hd is still \(hd.width) pixels wide") // prints "hd is still 1920 pixels wide"
这表明当hd被赋值给cinema时,是完整地复制了一个全新的Resolution结构给cinema,所以当cinema的属性被修改时,hd的属性不会变化。
下面的例子演示的是枚举类型:
enum CompassPoint { case North, South, East, West } var currentDirection = CompassPoint.West
let rememberedDirection = currentDirection
currentDirection = .East if rememberedDirection == .West { println("The remembered direction is still .West") } // prints "The remembered direction is still .West"
尽管经过几次赋值,rememberedDirection依然没有变化,这是因为在每一次赋值过程中,都是将数值类型完整地复制了过来。
3、类是引用类型
和数值类型不同引用类型不会复制整个实例,当它被赋值给另外一个常量或者变量的时候,而是会建立一个和已有的实例相关的引用来表示它。
下面是引用的示例,VideoMode被定义为一个类:
let tenEighty = VideoMode() tenEighty.resolution = hd
tenEighty.interlaced = true tenEighty.name = "1080i" tenEighty.frameRate = 25.0
分别将这个实例tenEighty的四个属性初始化,然后tenEighty被赋值给了另外一个叫alsoTenEighty的常量,然后alsoTenEighty的frameRate被修改了
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
由于类是一个引用类型,所以tenEighty和alsoTenEighty实际上是同一个实例,仅仅只是使用了不同的名称而已,我们通过检查frameRate可以证明这个问题:
println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") // prints "The frameRate property of tenEighty is now 30.0"
注意到tenEighty和alsoTenEighty是被定义为常量的,而不是变量。但是我们还是可以改变他们的属性值,这是因为它们本身实际上没有改变,它们并没有保存这个VideoMode的实例,仅仅只是引用了一个VideoMode实例,而我们修改的也是它们引用的实例中的属性。
特征操作
因为类是引用类型,那么就可能存在多个常量或者变量只想同一个类的实例(这对于数值类型的结构和枚举是不成立的)。
可以通过如下两个操作来判断两个常量或者变量是否引用的是同一个类的实例:
相同的实例(===)
不同的实例(!==)
使用这些操作可以检查:
if tenEighty === alsoTenEighty { println("tenEighty and alsoTenEighty refer to the same Resolution instance.") } // prints "tenEighty and alsoTenEighty refer to the same Resolution instance."
注意是相同的实例判断使用三个连续的等号,这和相等(两个等号)是不同的
实例相同表示的是两个变量或者常量所引用的是同一个类的实例
相等是指两个实例在数值上的相等,或者相同。
当你定义一个类的时候,就需要说明什么样的时候是两个类相等,什么时候是两个类不相等。更多内容可以从相等操作一章中获得。
指针
如果你有C,C++或者Objective-C的编程经验,你一定知道在这些语言中使用指针来引用一个内存地址。Swift中引用一个实例的常量或变量跟C中的指针类似,但是不是一个直接指向内存地址的指针,也不需要使用*记号表示你正在定义一个引用。Swift中引用和其它变量,常量的定义方法相同。
4、如何选择使用类还是结构
在代码中可以选择类或者结构来实现你所需要的代码块,完成相应的功能。但是结构实例传递的是值,而类实例传递的是引用。那么对于不同的任务,应该考虑到数据结构和功能的需求不同,从而选择不同的实例。
一般来说,下面的一个或多个条件满足时,应当选择创建一个结构:
结构主要是用来封装一些简单的数据值
当赋值或者传递的时候更希望这些封装的数据被赋值,而不是被引用过去
所有被结构存储的属性本身也是数值类型
结构不需要被另外一个类型继承或者完成其它行为
一些比较好的使用结构的例子:
一个几何形状的尺寸,可能包括宽度,高度或者其它属性,每个属性都是Double类型的
一个序列的对应关系,可能包括开始start和长度length属性,每个属性都是Int类型的
3D坐标系中的一个点,包括x,y和z坐标,都是Double类型
在其它情况下,类会是更好的选择。也就是说一般情况下,自定义的一些数据结构一般都会被定义为类。
Swift学习笔记(11)--类与结构体的更多相关文章
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记之-类和结构体
//类和结构体 import UIKit //类和结构体 /* 1.枚举enum.结构体struct和String.Array.Dictionary类型,都属于值传递类型,被赋值给新的常量或变量时传递 ...
- 【Swift】学习笔记(八)——类和结构体
1.类和结构体的定义 <pre name="code" class="html">struct Resolution { var width = 0 ...
- 【c# 学习笔记】类与结构体的区别
由于类与结构体在语法和使用上都非常类似,导致我们这些初学者容易混淆.为更好理解,特做以下区分记录: ① 语法上的区别在于,定义类要使用关键词class,而定义结构体则使用关键词struct. ② 结构 ...
- Swift学习笔记:类和结构
一.类和结构的异同 类和结构有一些相似的地方.它们都能够: 1. 定义一些能够赋值的属性: 2. 定义具有功能性的方法 3. 定义下标.使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现 ...
- 【Swift学习】Swift编程之旅---类和结构体(十三)
与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意:通常一个类 ...
- Bash脚本编程学习笔记07:循环结构体
本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...
- Bash脚本编程学习笔记06:条件结构体
简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式. if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现, ...
- Go语言学习笔记(四)结构体struct & 接口Interface & 反射
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...
随机推荐
- Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源代码
在android学习中,动作交互是软件中重要的一部分.当中的Scroller就是提供了拖动效果的类,在网上.比方说一些Launcher实现滑屏都能够通过这个类去实现.以下要说的就是上次Scroller ...
- Centos7+httpd+fastcgi+rails安装
搭建的环境: centos7 Apache/2.4.6 fastcgi2.4.6 rails4 在安装fastcgi的时候遇到了问题: 问题: .... .. In file included fro ...
- sublime text3 3143注册码
注册码: -– BEGIN LICENSE -– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 ...
- 【转】dig详解
[root@localhost ~]# dig www.a.com ; <<>> DiG 9.2.4 <<>> www.a.com ;; global ...
- python中对单例模式的理解
class Foo(object): instance = None def __init__(self): pass def process(self): ' @classmethod #版本1单例 ...
- Java类和对象8
按要求编写Java应用程序. (1)创建一个叫做People的类: 属性:姓名.年龄.性别.身高 行为:说话.计算加法.改名 编写能为所有属性赋值的构造方法: (2)创建主类: 创建一 ...
- 《剑指offer》字符串中的字符替换
一.题目描述 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 二.输入描 ...
- GoldenGate 应用系统升级
(仅复制DML时)源端和目标端数据库增减复制表 增加复制表 在GoldenGate的进程参数中,如果通过*来匹配所有表,因此只要符合*所匹配的条件,那么只要在源端建立了表之后GoldenGate就能自 ...
- 最小生成树(MST) prim() 算法 kruskal()算法 A - 还是畅通工程
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离. 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公 ...
- python BeautifulSoup 获取页面多个子节点中的各个节点的内容
页面html格式为 <tr bgcolor="#7bb5de"><td style="border-bottom: 1px solid #C9D8AD& ...