文档章节

Swift结构体与类

智捷课堂
 智捷课堂
发布于 2014/08/30 20:22
字数 2134
阅读 34
收藏 4

在面向过程的编程语言(如C语言)中,结构体用得比较多,但是面向对象之后,如在C++和Objective-C中,结构体已经很少使用了。这是因为结构体能够做的事情,类完全可以取而代之。
而Swift语言却非常重视结构体,把结构体作为实现面向对象的重要手段。Swift中的结构体与C++和Objective-C中的结构体有很大的差别,C++和Objective-C中的结构体只能定义一组相关的成员变量,而Swift中的结构体不仅可以定义成员变量(属性),还可以定义成员方法。因此,我们可以把结构体看做是一种轻量级的类。
Swift中的类和结构体非常类似,都具有定义和使用属性、方法、下标和构造器等面向对象特性,但是结构体不具有继承性,也不具备运行时强制类型转换、使用析构器和使用引用计等能力。
一、类和结构体定义
Swift中的类和结构体定义的语法也是非常相似的。我们可以使用class关键词定义类,使用struct关键词定义结构体,它们的语法格式如下:
class 类名 {
    定义类的成员
}
struct 结构体名 {
    定义结构体的成员
}
从语法格式上看,Swift中的类和结构体的定义更类似于Java语法,不需要像C++和Objective-C那样把接口部分和实现部分放到不同的文件中。
类名、结构体名的命名规范与枚举类型的要求是一样的。下面我们来看一个示例:
class Employee { //定义员工类
    var no : Int = 0 //定义员工编号属性
    var name : String = "" //定义员工姓名属性
    var job : String? //定义工作属性
    var salary : Double = 0 //定义薪资属性


    var dept : Department?  //定义所在部门属性
}


struct Department { //定义部门结构体
    var no : Int = 0 //定义部门编号属性
    var name : String = "" //定义部门名称属性
}
Employee是我们定义的类,Department是我们定义的结构体。在Employee和Department中我们只定义了一些属性。关于属性的内容我们将在下一章介绍。
Employee和Department是有关联关系的,Employee所在部门的属性dept与Department关联起来,它们的类图如下图所示。
 
我们可以通过下列语句实例化:
var emp = Employee()
var dept = Department()
Employee()和Department()是调用它们的构造器实现实例化,关于构造器我们会在14.1节介绍。
提示 实例化之后会开辟内存空间,emp和dept被称为“实例”,但只有类实例化的“实例”才能被称为“对象”。事实上,不仅仅是结构体和类可以实例化,枚举、函数类型和闭包开辟内存空间的过程也可以称为实例化,结果也可以叫“实例”,但不能叫“对象”。
二、再谈值类型和引用类型
数据类型可以分为:值类型和引用类型,这是由赋值或参数传递方式决定的。值类型就是在赋值或给函数传递参数时候,创建一个副本,把副本传递过去,这样在函数的调用过程中不会影响原始数据。引用类型就是在赋值或给函数传递参数的时候,把本身数据传递过去,这样在函数的调用过程中会影响原始数据。
在众多的数据类型中,我们只需记住:只有类是引用类型,其他类型全部是值类型。即便结构体与类非常相似,它也是值类型。值类型还包括整型、浮点型、布尔型、字符串、元组、集合和枚举。
Swift中的引用类型与Java中的引用类型是一样的,Java中的类也是引用类型。如果你没有Java经验,可以把引用类型理解为C、C++和Objective-C语言中的指针类型,只不过不需要在引用类型变量或常量前面加星号(*)。
下面我们看一个示例:

[html] view plaincopy

  1. var dept = Department() ①  

  2. dept.no = 10  

  3. dept.name = "Sales"         ②  

  4.   

  5.   

  6. var emp = Employee()        ③  

  7. emp.no = 1000  

  8. emp.name = "Martin"  

  9. emp.job = "Salesman"  

  10. emp.salary = 1250  

  11. emp.dept = dept             ④  

  12.   

  13.   

  14. func updateDept (dept : Department) {   ⑤  

  15.     dept.name = "Research"  ⑥  

  16. }  

  17.   

  18.   

  19. println("Department更新前:\(dept.name)")   ⑦  

  20. updateDept(dept)                ⑧  

  21. println("Department更新后:\(dept.name)")   ⑨  

  22.   

  23.   

  24. func updateEmp (emp : Employee) {   ⑩  

  25.     emp.job = "Clerk"       ⑪  

  26. }  

  27.   

  28.   

  29. println("Employee更新前:\(emp.job)")   ⑫  

  30. updateEmp(emp)              ⑬  

  31. println("Employee更新后:\(emp.job)")   ⑭  



上述代码第①~②行创建Department结构体实例,并设置它的属性。代码第③~④行创建Employee类实例,并设置它的属性。
为了测试结构体是否是值类型,我们在第⑤行代码定义了updateDept函数,它的参数是Department结构体实例。第⑥行代码dept.name = "Research"是改变dept实例。然后在第⑦行打印更新前的部门名称属性,在第⑧行进行更新,在第⑨行打印更新后的部门名称属性。如果更新前和更新后的结果一致,则说明结构体是值类型,反之则为引用类型。事实上第⑥行代码会有编译错误,错误信息如下。
Playground execution failed: error: <REPL>:34:15: error: cannot assign to 'name' in 'dept'
    dept.name = "Research"
    ~~~~~~~~~ ^
这个错误提示dept.name = "Research"是不能赋值的,这说明了dept结构体不能修改,因为它是值类型。其实有另外一种办法可以使值类型参数能够以引用类型传递,我们在第9章介绍过使用inout声明的输入输出类型参数,这里需要修改一下代码:
func updateDept (inout dept : Department) {
    dept.name = "Research"
}


println("Department更新前:\(dept.name)")
updateDept(&dept)
println("Department更新后:\(dept.name)")
我们不仅要将参数声明为inout,而且要在使用实例前加上&符号。这样修改后输出结果如下:
Department更新前:Sales
Department更新后:Research
相比之下,第⑩行代码是定义updateEmp函数,它的参数是Employee类的实例,我们不需要将参数声明为inout类型。在第⑪行修改emp没有编译错误,这说明Employee类是引用类型,在调用的时候不用在变量前面添加&符号,见代码第 行。输出结果如下:
Employee更新前:Salesman
Employee更新后:Clerk
这个结果再次说明了类是引用类。
三、引用类型的比较
我们在第4章介绍了基本运算符,提到了恒等于(===)和不恒等于(!===)关系运算符。===用于比较两个引用是否为同一个实例,!===则恰恰相反,它只能用于引用类型,也就是类的实例。
下面我们看一个示例:

[html] view plaincopy

  1. var emp1 = Employee()       ①  

  2. emp1.no = 1000  

  3. emp1.name = "Martin"  

  4. emp1.job = "Salesman"  

  5. emp1.salary = 1250  

  6.   

  7.   

  8. var emp2 = Employee()       ②  

  9. emp2.no = 1000  

  10. emp2.name = "Martin"  

  11. emp2.job = "Salesman"  

  12. emp2.salary = 1250  

  13.   

  14.   

  15.   

  16.   

  17. if emp1 === emp2                ③  

  18. {  

  19.     println("emp1 === emp2")  

  20. }  

  21. if emp1 === emp1                ④  

  22. {  

  23.     println("emp1 === emp1")  

  24. }  

  25.   

  26.   

  27. var dept1 = Department()    ⑤  

  28. dept1.no = 10  

  29. dept1.name = "Sales"  

  30.   

  31.   

  32. var dept2 = Department()    ⑥  

  33. dept2.no = 10  

  34. dept2.name = "Sales"  

  35.   

  36.   

  37. if dept1 == dept2   //编译失败  ⑦  

  38. {  

  39.     println("dept1 === dept2")  

  40. }  



上述代码第①行和第②行分别创建了emp1和emp2两个Employee实例。在代码第③行比较emp1和emp2两个引用是否为一个实例。可以看到,比较结果为False,也就是emp1和emp2两个引用不是一个实例,即便是它们内容完全一样,结果也是False,而第④行的比较结果为True。如果我们采用==比较,结果会如何呢?代码如下:
if emp1 == emp2 
{
    println("emp1 === emp2")
}
答案是有如下编译错误。==比较要求两个实例的类型(类、结构体、枚举等)必须要在该类型中重写==运算符,定义相等规则。同样的错误也会发生在第⑦行代码。
Playground execution failed: error: <REPL>:42:9: error: could not find an overload for '==' that accepts the supplied arguments
if emp1 == emp2
   ~~~~~^~~~~~~
代码第⑤行和第⑥行分别创建了dept1和dept2两个Department实例。在代码第⑦行使用==比较dept1和dept2两个值是否相等,不仅不能比较,而且还会发生编译错误,这在上面已经解释过了。
如果我们采用恒等于===比较dept1和dept2,结果会如何呢?代码如下:
if dept1 === dept2
{
    println("dept1 === dept2")
}

我们发现会有编译错误。===不能比较值类型,而Department结构体是值类型,因此不能使用===比较。




更多内容请关注国内第一本Swift图书《Swift开发指南》

本书交流讨论网站:http://www.51work6.com/swift.php

欢迎加入Swift技术讨论群:362298485

欢迎关注智捷iOS课堂微信公共平台


© 著作权归作者所有

上一篇: Swift静态方法
下一篇: Swift构造器重载
智捷课堂

智捷课堂

粉丝 40
博文 239
码字总数 215495
作品 0
东城
私信 提问
Swift讲解专题十——类与结构体

Swift讲解专题十——类与结构体 一、引言 Swift中的类与结构体十分相似,和Objective-C不同的是,Swift中的结构体不仅可以定义属性,也可以像类一样为其定义方法。 Swift中的类与结构体有如下...

珲少
2016/05/16
112
0
Swift 个人学习笔记 - 08: 类和结构体

本文章纯粹是中文版《The Swift Programming Language》的学习笔记,所以绝大部分的内容都是文中有的。本文是本人的学习笔记,不是正式系统的记录。仅供参考 以下还是有很多没看懂、不确定的...

amc
2017/03/10
0
0
swift4.1 学习回顾(9--16)

上一篇中,回顾了一到八节的内容,以及主要的知识点。本次学习做的不太好的一点就是没有及时的回顾,总是在不停的学习新知识,以至于前面的知识遗忘的比较多。现在回顾有一点亡羊补牢的感觉。...

小曼Study
2018/11/12
0
0
swift学习之类和结构体

类和结构体对比 Swift 中类和结构体有很多共同点。共同处在于: 定义属性用于存储值 定义方法用于提供功能 定义下标操作使得可以通过下标语法来访问实例所包含的值 定义构造器用于生成初始化值...

zh_iOS
2016/11/24
38
0
swift4.0-11 类和结构体

代码学习swift4.0, 类和结构体 // // main.swift // SwiftLearn11-类和结构体 // // Created by iOS on 2018/5/7. // Copyright © 2018年 weiman. All rights reserved. // import Foundat......

小曼Study
2018/05/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
5
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
8
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
10
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
6
0
PHP+Ajax微信手机端九宫格抽奖实例

PHP+Ajax结合lottery.js制作的一款微信手机端九宫格抽奖实例,抽奖完成后有收货地址添加表单出现。支持可以设置中奖概率等。 奖品列表 <div class="lottery_list clearfix" id="lottery"> ......

ymkjs1990
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部