在面向过程的编程语言(如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语言中的指针类型,只不过不需要在引用类型变量或常量前面加星号(*)。
下面我们看一个示例:
- var dept = Department() ①
- dept.no = 10
- 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
这个结果再次说明了类是引用类。
三、引用类型的比较
我们在第4章介绍了基本运算符,提到了恒等于(===)和不恒等于(!===)关系运算符。===用于比较两个引用是否为同一个实例,!===则恰恰相反,它只能用于引用类型,也就是类的实例。
下面我们看一个示例:
- 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结构体是值类型,因此不能使用===比较。
欢迎关注智捷iOS课堂微信公共平台
相关推荐
与类不同,结构体是值类型,这意味着每次传递或返回一个结构体时,实际上都是在复制整个结构体的值。 #### 二、Swift 结构体的基本定义 结构体使用 `struct` 关键字定义,并可以在其中声明属性(包括常量和变量)...
结构体与类相似,但不支持继承和引用计数。结构体更适合定义简单的、不涉及复杂生命周期管理的数据类型。结构体的优势在于它们是值类型,这意味着当结构体实例被赋值给新变量或作为函数参数传递时,会进行复制而非...
在 Swift 编程语言中,类(Class)和结构体(Structure)是两种用于创建自定义数据类型的核心构造。尽管它们在功能上有许多相似之处,但它们之间也存在一些关键的区别,这些区别影响着开发者在不同场景下的选择。...
Swift 结构体 Swift 结构体是构建代码所用的一种通用且灵活的构造体。 我们可以为结构体定义属性(常量、变量)和添加方法,从而扩展结构体的功能。 与 C 和 Objective C 不同的是: 结构体不需要包含实现文件和...
结构体与类相似,但有以下几点不同: 1. 结构体没有继承:Swift中的结构体不能从其他结构体或类继承,而类可以继承其他类。 2. 结构体的复制行为:当你将结构体实例赋值给新的变量时,会创建一个新的结构体实例,而...
在Swift编程语言中,有效地管理和缓存大量数据是应用程序性能优化的关键环节。标题"swift-可以直接把模型数组归档转成data完美解决大量数据缓存的问题"提到了一种利用Swift的归档(Archiving)机制将模型数组转换为...
以下是关于Swift结构体的详细解释: 1. **定义结构体**: 使用`struct`关键字来定义一个结构体,后跟结构体的名称,接着是花括号`{}`,其中包含了结构体的属性和方法定义。例如: ```swift struct MyStruct { ...
7. **结构体与类**:Swift中的结构体和类都支持方法、属性和初始化器,但结构体是值类型,类是引用类型,这影响了它们的复制和赋值行为。 8. **自动引用计数(Automatic Reference Counting, ARC)**:Swift使用ARC...
书中涵盖的主题包括Swift语言的内置集合、可选值、函数灵活性、结构体与类以及未来发展方向等多个方面。现在,让我们详细探讨这些知识点: 1. 内置集合 Swift拥有强大的内置集合类型,包括数组(Arrays)、字典...
5. Swift中使用:现在,Swift代码可以通过实例化Objective-C类来访问和修改C++结构体。 ```swift let obj = MyClass() obj.setMyStructWithInt(10, doubleValue: 3.14) let myStruct = obj.myStruct ``` 此外,...
这篇文章将深入探讨 Swift 3.0 中类与结构体的基本概念、它们之间的区别以及如何使用它们。 首先,Swift 的类和结构体有多个共同点。它们都可以: 1. 定义属性(properties),用于存储数据。 2. 定义方法...
Swift是一种强大的编程语言,它支持面向对象编程以及面向过程编程,这主要体现在它同时提供了类(Class)和结构体(Struct)两种数据类型。这两者有很多相似之处,但也有本质的区别,选择使用哪种取决于具体需求。 ...
该工具的工作原理是解析输入的JSON样本,然后生成相应的Swift结构体或类,每个JSON键映射为一个Swift属性。 要使用json2swift,首先确保你的macOS系统已经安装了Homebrew,这是一个包管理器,可以方便地安装命令行...
4. **结构体与类** (`10-structures`和`13-classes`): Swift支持面向对象编程,包括结构体和类。结构体适合存储值类型的数据,而类则用于表示引用类型,可以继承、封装和多态。 5. **属性** (`11-properties`): ...
在Swift编程中,有时我们可能遇到这样的情况:系统的标准类无法完全满足我们的需求,因此我们需要对其进行扩展,添加一些自定义的属性。在这种情况下,我们通常会使用分类(Category)或者扩展(Extension)来实现。...
五、结构体与类的比较 虽然结构体和类都可以封装数据和行为,但有几点关键区别: 1. 结构体是值类型,而类是引用类型。 2. 类支持继承,结构体则不支持。 3. 类可以使用`deinit`方法实现析构,结构体没有析构过程。 ...
1. 结构体与枚举:结构体是值类型,而枚举提供了一种强大的方式来定义一组相关的值。 2. 类:类是引用类型,支持继承、多态和属性观察者,适用于需要引用计数的情况。 3. 初始化与析构:Swift中的初始化过程严谨,...
- **结构体与枚举**:Swift支持结构体和枚举作为自定义数据类型,如定义一个`Entry`结构体表示日记条目。 2. **UI设计**: - **Storyboard**:Xcode中的Storyboard用于可视化布局,可以创建界面元素如UILabel、...
- 结构体和类:Swift允许开发者使用结构体和类来定义自己的数据类型。文档可能在这一章节中讲解了结构体和类的区别、如何选择使用结构体还是类,以及它们的继承、封装、多态等面向对象编程的基础知识。 - 函数:...
3. **结构体与类**:Swift中结构体和类的使用场景有明显区分,结构体更适合值类型,而类适合引用类型。理解两者的内存管理差异对性能优化至关重要。 4. **协议与扩展**:协议提供了接口规范,而扩展则可以在不修改...