苹果新的编程语言 Swift 语言进阶(七)--枚举、结构、类

时间:2023-04-02 12:28:20

Swift语言中,具有类特征的类型包括三种,即枚举类型、结构类型(包括基本类型,基本类型实际都是结构类型的特例)、类。其中枚举类型、结构类型是属于值类型,类属于引用类型。三种类型都可以添加属性、方法、下标方法,能够使用扩展进行功能扩展,使用协议等。

一、 枚举

枚举定义了一种包含一组相关值的公共类型。枚举是Swift中的一种与类类似的类型,具有许多传统类才有的特征,例如计算属性、实例方法,能够通过扩展或协议增强功能等。

1.1 枚举定义

Swift 语言的枚举类型的定义语法如下:

enum CompassPoint {

case North

case South

case East

case West

}

枚举语法以一个关键字enum来标识,enum后面包含一个枚举类型名字,枚举定义全部放到一对大括号中。

在枚举中定义的值称为枚举成员值,用case关键字来指示一个新的枚举成员值。

与C和Objective-C语言的枚举类型不同的是:在Swift中不需要为枚举成员分配一个默认的整数值。

如果为枚举成员提供值,该值可以是一个字符串、一个字符或者是一个任意整数或浮点数。

枚举成员值可以定义到一行中,并用逗号分割。

enum Planet {

case Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune

}

每个新定义的枚举都属于一种新的独立的类型。

1.2 枚举的使用

可以为一个常量或变量分配一种枚举类型的值,如:

var directionToHead
=CompassPoint.West

以上定义的变量directionToHead可以推断为是一种CompassPoint类型的枚举变量,因此你可以设置该变量为CompassPoint类型的其它值,如:

directionToHead = .East //枚举类型被省略

枚举也能够在switch语句中使用,用来匹配独立的枚举值:

directionToHead = .South

switch directionToHead
{

case .North:

println("Lots of planets
have a north")

case .South:

println("Watch out
for penguins")

case .East:

println("Where the
sun rises")

case .West:

println("Where the
skies are blue")

}

1.3 为枚举成员分配相关值

Swift中能够为每一个枚举成员规定一个任意类型的相关值,并且为每个枚举成员规定的相关值的类型可以不同。

enum Barcode {

case UPCA(Int,Int,Int)

case QRCode(String)

}

该例子定义了一个类型为Barcode的枚举类型,并定义了两个枚举值UPCA
和QRCode,并可以为枚举值UPCA 分配一个多元组类型的相关值,为QRCode分配一个字符串类型的相关值,该例子没有为枚举值本身指定任何类型的值。

可以使用以上定义的枚举为一个常量或变量赋值,如:

var productBarcode
=Barcode.UPCA(8,85909_51226,3)

该例子为变量 productBarcode分配了一个Barcode.UPCA枚举值,为其分配的相关的多元组类型的值为(8,85909_51226,3)。

然后该变量productBarcode可以设置为带字符串类型相关值的另外的一个枚举值:

productBarcode = .QRCode(“ABCDEFGHIJKLMNOP”)

还可以在switch语句中使用该枚举,并通过绑定常量或变量的方式引出其带有的相关类型的值:

switch productBarcode
{

case .UPCA(let numberSystem,let identifier,let check):

println("UPC-A with
value of\(numberSystem),\(identifier),\(check).")

case .QRCode(let productCode):

println("QR code with
value of\(productCode).")

}

如果枚举成员的所有的相关值都作为常量被引出,或者所有的相关值都作为变量形式被引出,以上语法还可以简写为如下形式:

switch productBarcode
{

case let
.UPCA(numberSystem,identifier,check):

println("UPC-A with
value of\(numberSystem),\(identifier),\(check).")

case let
.QRCode(productCode):

println("QR code with
value of\(productCode).")

}

1.4 为枚举分配原始值

除了为枚举成员分配相关的值外,还能为每个枚举成员预分配一个同类型的原始值。这与C 语言为枚举成员分配一个整数值类似,但Swift定义的原始值的类型可以是字符串、字符、或任意的整数或浮点数类型等,如:

enum ASCIIControlCharacter:Character
{

case Tab
="\t"

case LineFeed
="\n"

case CarriageReturn
="\r"

}

该例子中,定义了一个含有三个枚举成员的枚举类型ASCIIControlCharacter,并指定其原始类型为字符类型,并为每个枚举成员分配一个字符类型的默认原始值。

与C语言为枚举成员指定值类似,Swift要求为枚举的每个枚举成员分配的原始值必须在枚举声明内唯一。当使用整数类型的原始值时,枚举成员的其它原始值如果没有指定,其能够在第一个枚举成员定义值的基础上自动加1,如下所示:

enum Planet:Int
{

case Mercury
=1,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune

}

为枚举成员定义的原始值与为枚举成员分配的相关值不同,枚举成员的原始值是在枚举第一次定义时被分配的,而枚举成员的相关值虽然其类型也是在枚举定义时指定,但其值是在使用枚举类型创建一个常量或变量时设置的。

在Swift中,能够使用枚举成员的toRaw方法来获取枚举成员的原始值:

let earthsOrder = Planet.Earth.toRaw()

相反,也可以使用枚举类型的fromRaw方法来返回对应原始值的枚举成员,该方法返回的是一个选项,因为其值可能存在也可能不存在。如下所示。

let possiblePlanet
=Planet.fromRaw(9)

// 返回对应原始值为9的枚举Planet的枚举成员。返回的是一个Planet? 选项类型,在例子所示情况下该值不存在,返回的是一个nil。

二 结构与类

2.1 两者比较

在Swift中,结构和类功能上几乎相同,两者都具有如下相同的功能:

1) 可以定义属性,用来存储值;

2) 可以定义方法,用来提供功能;

3) 可以定义一个脚本方法,用来使用脚本语法来存取它们的值;

4) 能够定义初始化方法来设置它们的初始状态;

5) 能够扩展来增加原先没有实现的功能;

6) 能够遵从相关协议来提供确定类型的标准功能。

类在以下方面与结构存在差别:

1) 类能够继承,一个类能够继承它的超类的特性,而结构不能继承;

2) 类允许在运行时检查和解释一个类实例的类型;

3) 类可以带有析构函数,允许类的实例释放它所分配的任何资源;

4) 引用计数允许一个类实例有多个引用。

5) 结构在代码中总是以复制方式来传递,而不使用引用计数。

2.2 类和结构的定义和实例化

类和结构的定义采用相似的语法,类使用class关键字来指示,结构使用struct关键字来指示。

struct Resolution {

var width
=0

var height
=0

}

class VideoMode {

var resolution
=Resolution()

var interlaced
=false

var frameRate
=0.0

var name:String?

}

每个新定义的类或结构都定义了一种新的类型。

上面例子定义了一种称作Resolution的新的结构类型,其中包含和定义了两个变量类型的属性。还定义了一个称作VideoMode的新类,该类定义和包含四个变量类型的属性,其第一个属性resolution还使用了刚刚定义的结构Resolution的实例进行了初始化。

类和结构中定义的变量或常量类型的属性像通常变量和常量一样进行初始化和赋值,属性的类型可以根据为其提供的初始值进行推断。

为类和结构创建实例的语法相同:

let someResolution
=Resolution()

let someVideoMode =VideoMode()

该例子采用了结构和类初始化最简单的语法形式(结构和类的类型名面跟着一对圆括号)。该初始化语法为结构和类创建了一个新的各自的实例,并赋值给两个常量,两个实例的属性也在该初始化方法中被初始化为它们的默认值。

在Swift中,所有的结构类型都会自动产生一个参数初始化方法,可以使用该方法来初始化和创建结构的新的实例及其成员属性,新创建实例的属性的初始值使用该初始化方法的参数传进来的值,如:

let vga
=Resolution(width:640,height:480)。

而类没有提供相对应的默认的参数初始化方法。

在Swift中,与脚本语言类似,可以使用点语法的形式来存取一个结构或类实例的属性以及子属性,即读取和设置其值:

读取属性的值:

println("The width of someResolution is\(someResolution.width)”)

println("The width of someVideoMode is\(someVideoMode.resolution.width)”)

设置一个属性的值:

someVideoMode.resolution.width
= 1280

2.3  结构、类与枚举的类型

在Swift中,结构和枚举与其它基本类型(整型、浮点类型、布尔类型、字符串、数组和词典,这些类型其实都是以结构类型实现的)一样属于值类型。这意味着它们在分配给一个变量或常量时或当它作为参数传送给一个函数时,它们的实例以及它们包含的所有作为值类型的属性一一被拷贝。

在Swift中,为了提供性能,拷贝采用延迟拷贝的机制,即在实际用到时才拷贝。

let 
   hd = Resolution(width:1920, height:1080)

var cinema =hd

在该例子中,由于Resolution是一个结构类型,因此常量hd和变量cinema属于Resolution结构类型的不同实例,因为在为变量cinema赋值时发生了拷贝行为。

与结构和枚举不同,类的类型属于引用类型。引用类型的实例在分配给一个变量或常量时或当它作为参数传送给一个函数时,没有拷贝发生。

let tenEighty
=VideoMode()

tenEighty.frameRate
= 25.0

let alsoTenEighty
=tenEighty

alsoTenEighty.frameRate =30.0

由于VideoMode属于类,因此现在两个常量tenEighty和alsoTenEighty引用的是相同的VideoMode实例,只是对应相同实例的不同的名字,因此这两个常量的属性值frameRate现在都等于30.0。

注意上面的tenEighty和alsoTenEighty被声明为两个常量,而不是变量,这是因为tenEighty和alsoTenEighty本身存储的只是VideoMode的实例的引用值,而不是VideoMode实例本身,因此你通过它们对引用的类实例的属性的改变,改变是类实例本身的属性,而不是引用本身。

由于类是引用类型,就如以上例子所示,多个变量或常量可能引用一个类的相同的实例。为了判断两个常量或变量是否引用的是一个类的相同实例,Swift提供了两个引用比较操作符: ‘===’与 ‘!==’。可以使用这两个操作符来检查两个常量或变量是否引用的是相同的实例:

if tenEighty ===alsoTenEighty
{

println("tenEighty
and alsoTenEighty refer to the same Resolution instance.")

}

在Swift中,一个常量或变量引用一个类的实例,这与C语言中的指针类似,但在Swift 中,引用不是直接指向内存中一个地址,因此不需要使用C语言中类似的指针符号’*’,用来代表一个引用或指针。

版权所有,请转载是清楚注明链接和出处,谢谢!