在面向过程的编程语言(如C语言)中,结构体用得比较多,可是面向对象以后,如在C++和Objective-C中,结构体已经不多使用了。这是由于结构体可以作的事情,类彻底能够取而代之。
而Swift语言却很是重视结构体,把结构体做为实现面向对象的重要手段。Swift中的结构体与C++和Objective-C中的结构体有很大的差异,C++和Objective-C中的结构体只能定义一组相关的成员变量,而Swift中的结构体不只能够定义成员变量(属性),还能够定义成员方法。所以,咱们能够把结构体看作是一种轻量级的类。
Swift中的类和结构体很是相似,都具备定义和使用属性、方法、下标和构造器等面向对象特性,可是结构体不具备继承性,也不具有运行时强制类型转换、使用析构器和使用引用计等能力。
1、类和结构体定义
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被称为“实例”,但只有类实例化的“实例”才能被称为“对象”。事实上,不只仅是结构体和类能够实例化,枚举、函数类型和闭包开辟内存空间的过程也能够称为实例化,结果也能够叫“实例”,但不能叫“对象”。
2、再谈值类型和引用类型
数据类型能够分为:值类型和引用类型,这是由赋值或参数传递方式决定的。值类型就是在赋值或给函数传递参数时候,建立一个副本,把副本传递过去,这样在函数的调用过程当中不会影响原始数据。引用类型就是在赋值或给函数传递参数的时候,把自己数据传递过去,这样在函数的调用过程当中会影响原始数据。
在众多的数据类型中,咱们只需记住:只有类是引用类型,其余类型所有是值类型。即使结构体与类很是类似,它也是值类型。值类型还包括整型、浮点型、布尔型、字符串、元组、集合和枚举。
Swift中的引用类型与Java中的引用类型是同样的,Java中的类也是引用类型。若是你没有Java经验,能够把引用类型理解为C、C++和Objective-C语言中的指针类型,只不过不须要在引用类型变量或常量前面加星号(*)。
下面咱们看一个示例:
php
[html] view plaincopyhtml
var dept = Department() ① 编程
dept.no = 10 swift
dept.name = "Sales" ② 微信
var emp = Employee() ③ 闭包
emp.no = 1000 编程语言
emp.name = "Martin" 函数
emp.job = "Salesman" 测试
emp.salary = 1250 网站
emp.dept = dept ④
func updateDept (dept : Department) { ⑤
dept.name = "Research" ⑥
}
println("Department更新前:\(dept.name)") ⑦
updateDept(dept) ⑧
println("Department更新后:\(dept.name)") ⑨
func updateEmp (emp : Employee) { ⑩
emp.job = "Clerk" ⑪
}
println("Employee更新前:\(emp.job)") ⑫
updateEmp(emp) ⑬
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
这个结果再次说明了类是引用类。
3、引用类型的比较
咱们在第4章介绍了基本运算符,提到了恒等于(===)和不恒等于(!===)关系运算符。===用于比较两个引用是否为同一个实例,!===则偏偏相反,它只能用于引用类型,也就是类的实例。
下面咱们看一个示例:
[html] view plaincopy
var emp1 = Employee() ①
emp1.no = 1000
emp1.name = "Martin"
emp1.job = "Salesman"
emp1.salary = 1250
var emp2 = Employee() ②
emp2.no = 1000
emp2.name = "Martin"
emp2.job = "Salesman"
emp2.salary = 1250
if emp1 === emp2 ③
{
println("emp1 === emp2")
}
if emp1 === emp1 ④
{
println("emp1 === emp1")
}
var dept1 = Department() ⑤
dept1.no = 10
dept1.name = "Sales"
var dept2 = Department() ⑥
dept2.no = 10
dept2.name = "Sales"
if dept1 == dept2 //编译失败 ⑦
{
println("dept1 === dept2")
}
上述代码第①行和第②行分别建立了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课堂微信公共平台