在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版本)做了一些修改,简化了设计理念,理解上也更容易一些。

Swift类和结构体的更多相关文章

  1. swift 类和结构体

    1:类和结构体定义 类和结构体分别通过关键字class 和struct定义. swift的编码风格是类class和结构体struct名字使用大写字母开头的匈牙利表示法,相反的.类的方法和属性则用小写字 ...

  2. swift 类 与 结构体

    这两天突然有人问我  swift里面 类和 结构体  有什么区别? 说实在的本人目前不太看好swift,相信很多人也是,oc 都 很成熟了. 本人目前不打算深入了解swift的原因swift  语言 ...

  3. Swift类与结构体

    类和结构体有很多共性: 定义属性存储数据 定义方法执行功能处理 定义下标,通过下标访问他们的值 初始化他们的状态 通过扩展(Extension)扩展其功能 遵守协议(Protocol),协议提供一种特 ...

  4. Swift: 类与结构体

    对比类与结构体 类与结构体有许多的相同点,它们都可以: 定义属性来存储值: 定义方法来提供功能: 定义下标操作: 定义初始化函数: 扩展它的默认的实现: 遵从协议: 类有一些额外的能力,但是结构体没有 ...

  5. Swift类和结构体定义-备

    Swift中的类和结构体定义的语法是非常相似的.类使用class关键词定义类,使用struct关键词定义结构体,它们的语法格式如下: class 类名 { 定义类的成员 } struct 结构体名 { ...

  6. Swift 类和结构体的简单认识

    类和结构体的共同点: 定义属性用于存储值 定义方法用于提供功能 定义附属脚本用于访问值 通过拓展增加默认实现的功能 定义构造器用于生成初始化值 实现协议以提供某种标准功能 类是引用类型 结构体是值类型 ...

  7. Swift - 类和结构体的区别

    类和结构体有许多相同之处,也有许多不同之处. 二者区别如下: 1,类可以继承和扩展,结构体不可以 2,可以让一个类的实例来反初始化,释放存储空间,结构体做不到 3,类的对象是引用类型,而结构体是值类型 ...

  8. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  9. 【Swift学习】Swift编程之旅---类和结构体(十三)

    与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件.你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口. 注意:通常一个类 ...

随机推荐

  1. 【转载】面向切面编程(AOP)学习

    看到这篇文章,学习一下:http://www.ciaoshen.com/2016/10/28/aop/ 想理清一下从“动态代理”,到 “注释”,到“面向切面编程”这么一个技术演进的脉络. 只想讲清楚两 ...

  2. 拦截器及 Spring MVC 整合

    一.实验介绍 1.1 实验内容 本节课程主要利用 Spring MVC 框架实现拦截器以及 Spring MVC 框架的整合. 1.2 实验知识点 Spring MVC 框架 拦截器 1.3 实验环境 ...

  3. epoll 浅析以及 nio 中的 Selector

    首先介绍下epoll的基本原理,网上有很多版本,这里选择一个个人觉得相对清晰的讲解(详情见reference): 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作 ...

  4. 仰视源代码,实现strcpy

    编程实现字符串的拷贝,不能用库函数. 一般的刚開始学习的人也许能写出来.可是要写的非常完美那就须要基本功了. char* strcpy(char* strDest, const char* strSr ...

  5. PC和手机怎么实现绝对居中?

    示例1(懒人之家): http://www.51xuediannao.com/js/nav/360buy_nav.html 示例2(google官方):

  6. Vue.js 使用cordova camera插件调取相机

    本文给出在vue.js里如何使用cordova的插件完成调取相机及图库,并完成图片上传的操作.具体的操作步骤如下 第一步:在cordova项目下安装cordova-plugin-camera插件 co ...

  7. STL之set具体解释(二)

    首先来看看set集合容器: set集合容器实现了红黑树的平衡二叉树数据结构.在插入元素时它会自己主动调整二叉树的排列,把该元素放到适当的位置,而且 保证左右子树平衡.平衡二叉检索树採用中序遍历算法. ...

  8. HttpUtility.UrlEncode,Request.RawUrl,HttpUtility.UrlDecode,HttpUtility.UrlPathEncode,Uri.EscapeDataString

    碰到同样问题, 记录一下. 引自:https://www.cnblogs.com/ken-admin/p/5826480.html HttpUtility.UrlDecode(url),从Encode ...

  9. kubernetes之创建基于名称空间的内存和cpu限额示例

    系列目录 首先我们创建一个名称空间 kubectl create namespace quota-mem-cpu-example 创建资源配额 apiVersion: v1 kind: Resourc ...

  10. ubuntu环境eclipse配置

    ubuntu环境eclipse配置 首先下载Eclipse和JDK: 然后将上边两个压缩包解压到安装文件夹(如;/home/linux/softwares/java).然后配置/etc/profile ...