在C++中,相信不会有太多人去详细考究结构体和类的区别,因为二者关系实在不大。但在Swift中,结构体和类的关系非常大,它们的组成部分都包括:初始化器、实例方法、实例属性、类型属性、类型方法等等;二者也自然有很多的不同点,最大的不同点要数「类是引用类型,结构体是值类型」。本文着重对比阐述类和结构体的本质区别和它们的使用。

类和结构体对比

在Swift中,类和结构体有很多的共同点,包括:

  • Define properties to store values.
  • Define methods to provide functionality.
  • Define subscripts to provide access to their values using subscript syntax.
  • Define initializers to set up their initial state.
  • Be extended to expend their functionality beyond a default implementation.
  • Conform to protocols to provide standard functionality of a certain kind.

和结构体相比,类还具有一些结构体不具备的特性:

  • Inheritance enables one class to inherit the characteristics of another.(结构体是不允许继承或被继承的)
  • Type casting enables you to check and interpret the type of a class instance at runtime.(结构体不存在多态,自然不存在所谓的「类型转换」了)
  • Deinitializers enable an instance of a class to free up any resources it has assigned.
  • Reference counting allows more than one reference to a class instance.

类和结构体的定义

类和结构体有着类似的定义方式。我们通过关键字class和struct来分别表示类和结构体,并在一对大括号{}中定义它们的具体内容,如下定义了一个结构体类型Resolution(用来描述一个显示器的像素分辨率)和一个类类型VideoMode(用来描述一个视频显示器的特定模式):

struct Resolution {
var width =
var height =
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
实例以及属性访问

定义结构体和类实例语法几乎一样:

let someResolution = Resolution()
let someVideoMode = VideoMode()

和其他大多数语言一样,访问实例的属性使用.操作符。但是与OC不同的是,Swift允许直接设置结构体属性的子属性(在OC中可不允许),如下:

println("The width of someVideoMode is \(someVideoMode.resolution.widt
h)")
// 输出 "The width of someVideoMode is 0"
someVideo.resolution.width =
println("The width of someVideoMode is now \(someVideoMode.resolution.
width)")
// 输出 "The width of someVideoMode is now 1280"

结构体的逐一成员构造器

Swift为类和结构体都提供了默认的初始化构造器,其中有一个为结构体特别提供的默认构造器叫「逐一成员构造器」(memberwise initializer)。简而言之,使用该构造器,在创建实例时可以通过属性的名称设置它们的属性值,如下:

let vga = resolution(width:, height:)

更多关于结构体的「逐一成员构造器」信息,参考这里

值类型和引用类型

类是引用类型

众所周知,类类型是「引用类型」。换句话说,对类类型变量赋值(譬如函数/方法的参数传值、返回值、变量赋值等),实际上操作的只是对象指针的拷贝。

结构体和枚举都是值类型

与「引用类型」对应的是「值类型」。值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是对其进行拷贝。

在Swift中,所有的基本类型都是值类型。换句话说,整型、浮点型、布尔值、字符串、数组、set、字典都是值类型,更进一步说,它们都是「结构体」类型。

恒等运算符

考虑到类是引用类型,有可能有多个常量或变量在后台同时引用同一个实例(当然,这对属于值类型的结构体和枚举而言是不成立的)。所以在很多时候需要判断两个常量或者变量是否引用同一个类实例,Swift为我们提供了两个运算符===!==,它们被称为「恒等运算符」(Identity Operators)。关于它们的用法就不啰嗦了,一眼就能看出来。

类和结构体的选择

相对于其他语言譬如C++,Swift中赋予了结构体更强大的功能,它和类类型有非常多的相似之处,都可以用来自定义数据类型,那么该如何选用呢?

结构体实例总是通过「值传递」,类实例总是通过「引用传递」。这意味着二者适用于不同的任
务。按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:

  • 结构体的主要目的是用来封装少量相关简单数据值;
  • 有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用;
  • 任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用;
  • 结构体不需要去继承另一个已存在类型的属性或者行为;

P.S:个人觉得,有了一定的使用经历之后,这个问题便不再是问题了,可能会变成一种下意识。

集合类型的赋值和拷贝行为

姑且也把String认为是集合类型吧!

在OC中,NSString、NSArray、NSSet、NSDictionary以及相关类型都是类类型,因此,在传递过程中,它们的传递方式默认情况都是引用传递(对于属性,如果指定copy修饰词则有所不同,相对而言,比较复杂)。

但是在Swift中,正如前文所述,String、Array、Set、Dictionary的本质都是「结构体」。无论在什么场合,它们的传递方式都是值传递。官方文档是这么描述的:

Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.

P.S:在第一个版本的《The Swift Programming Language》中有不同的描述,大概的意思是:

Swift中数组(Array)和字典(Dictionary)类型均以结构体的形式实现。然而当数组被赋予一个常量或变量,或被传递给一个函数或方法时,数组(以及字典)的拷贝行为和其它结构体有些许不同。在Swift的后台中,只有确有必要,实际(actual)拷贝才会被执行。Swift管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。

P.P.S:上述这段话摘自《The Swift Programming Language》第一个版本中译版。可以看出,相对于第一个版本,当下Swift(1.2版本)做了一些修改,简化了设计理念,理解上也更容易一些。

最新文章

  1. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition
  2. 修改ubuntu中usr文件夹的权限后,sudo后出现sudo:must be setuid root问题的解决方案
  3. tomcat 配置ssi
  4. java时间和日期类型
  5. UML 简单介绍
  6. Coursera台大机器学习课程笔记13 -- Regularization
  7. July 18th, Week 30th Monday, 2016
  8. AMQ学习笔记 - 10. Spring-JmsTemplate之浏览
  9. UITableView学习笔记
  10. Android(java)学习笔记187:Android中操作XML数据(使用Pull解析器)
  11. Traffic Lights - SGU 103(最短路)
  12. (转载)python多行注释
  13. securecrt在linux与windows之间传输文件(转)
  14. Session获取不到的情况及解决办法(源码解析)
  15. 【转】nagios使用带url的check_http检测主机
  16. PyTorch中ReLU的inplace
  17. 怎样设置高效的IIS
  18. c++ vector push_back对象的时候存起来的是拷贝
  19. CentOS 部署.net core 2.0 项目
  20. 第一节,tensorflow基础构架

热门文章

  1. sublime快捷键设置
  2. spring secrity 一些常用小知识
  3. IOS_DatePicker_PickerView_SegmentControl_键盘处理
  4. C++学习总结2
  5. android自己定义渐变进度条
  6. 基于multiprocessing和threading实现非阻塞的GUI界面显示
  7. caffe搭建--缺少 skimage-缺少 google.protobuf.internal.-caffe搭建--ipython--ubuntu16.04+ caffe+ ipython
  8. LeetCode(125)题解--Valid Palindrome
  9. vs添加对dll的引用
  10. static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符