您的位置:首页 > 移动开发 > Swift

Swift类和结构体

2015-06-29 17:50 369 查看
在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 = 0
var height = 0
}


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 = 12880
println("The width of someVideoMode is now \(someVideoMode.resolution.
width)")
// 输出 "The width of someVideoMode is now 1280"


结构体的逐一成员构造器

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

let vga = resolution(width:640, height:480)


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

值类型和引用类型

类是引用类型

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

结构体和枚举都是值类型

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

在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版本)做了一些修改,简化了设计理念,理解上也更容易一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: