Swift学习:2.9 类和结构体
参考Swift 官方教程《The Swift Programming Language》中文版
类和结构体类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照常量、变量以及函数所规定的语法规则来定义属性和添加方法。 与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。
类和结构体对比Swift 中类和结构体有很多共同点。共同处在于:
更多信息请参见属性,方法,下标脚本,初始过程,扩展,和协议。 与结构体相比,类还有如下的附加功能:
更多信息请参见继承,类型转换,初始化,和自动引用计数。
定义类和结构体有着类似的定义方式。我们通过关键字 class SomeClass {
// class definition goes here
}
struct SomeStructure {
// structure definition goes here
}
以下是定义结构体和定义类的示例: 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()
结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如 属性访问通过使用点语法(dot syntax),你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接: println("The width of someResolution is (someResolution.width)")
// 输出 "The width of someResolution is 0"
在上面的例子中, 你也可以访问子属性,如 println("The width of someVideoMode is (someVideoMode.resolution.width)")
// 输出 "The width of someVideoMode is 0"
你也可以使用点语法为属性变量赋值: someVideoMode.resolution.width = 1280
println("The width of someVideoMode is now (someVideoMode.resolution.width)")
// 输出 "The width of someVideoMode is now 1280"
结构体类型的成员逐一构造器(Memberwise Initializers for structure Types)所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中: let vga = Resolution(width:640,height: 480)
与结构体不同,类实例没有默认的成员逐一构造器。构造过程章节会对构造器进行更详细的讨论。 结构体和枚举是值类型值类型被赋予给一个变量,常数或者本身被传递给一个函数的时候,实际上操作的是其的拷贝。 在之前的章节中,我们已经大量使用了值类型。实际上,在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Booleans)、字符串(string)、数组(array)和字典(dictionaries),都是值类型,并且都是以结构体的形式在后台所实现。 在 Swift 中,所有的结构体和枚举都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。 请看下面这个示例,其使用了前一个示例中 let hd = Resolution(width: 1920,height: 1080)
var cinema = hd
在以上示例中,声明了一个名为 然后示例中又声明了一个名为 下面,为了符合数码影院放映的需求(2048 像素宽,1080 像素高), cinema.width = 2048
这里,将会显示 println("cinema is now (cinema.width) pixels wide")
// 输出 "cinema is now 2048 pixels wide"
然而,初始的 println("hd is still (hd.width ) pixels wide")
// 输出 "hd is still 1920 pixels wide"
在将 枚举也遵循相同的行为准则: enum CompassPoint {
case North,South,East,West
}
var currentDirection = CompassPoint.West
let rememberedDirection = currentDirection
currentDirection = .East
if rememberDirection == .West {
println("The remembered direction is still .West")
}
// 输出 "The remembered direction is still .West"
上例中 类是引用类型与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,操作的是引用,其并不是拷贝。因此,引用的是已存在的实例本身而不是其拷贝。 请看下面这个示例,其使用了之前定义的 let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
以上示例中,声明了一个名为 然后, let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
因为类是引用类型,所以 下面,通过查看 println("The frameRate property of tenEighty is now (tenEighty.frameRate)")
// 输出 "The frameRate property of theEighty is now 30.0"
需要注意的是 恒等运算符因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个类实例。(对于结构体和枚举来说,这并不成立。因为它们作为值类型,在被赋予到常量、变量或者传递到函数时,其值总是会被拷贝。) 如果能够判定两个常量或者变量是否引用同一个类实例将会很有帮助。为了达到这个目的,Swift 内建了两个恒等运算符:
以下是运用这两个运算符检测两个常量或者变量是否引用同一个实例: if tenEighty === alsoTenTighty {
println("tenTighty and alsoTenEighty refer to the same Resolution instance.")
}
//输出 "tenEighty and alsoTenEighty refer to the same Resolution instance."
请注意
当你在定义你的自定义类和结构体的时候,你有义务来决定判定两个实例“相等”的标准。在章节运算符函数(Operator Functions)中将会详细介绍实现自定义“等于”和“不等于”运算符的流程。 指针如果你有 C,C++ 或者 Objective-C 语言的经验,那么你也许会知道这些语言使用指针来引用内存中的地址。一个 Swift 常量或者变量引用一个引用类型的实例与 C 语言中的指针类似,不同的是并不直接指向内存中的某个地址,而且也不要求你使用星号(*)来表明你在创建一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。 类和结构体的选择在你的代码中,你可以使用类和结构体来定义你的自定义数据类型。 然而,结构体实例总是通过值传递,类实例总是通过引用传递。这意味两者适用不同的任务。当你在考虑一个工程项目的数据构造和功能的时候,你需要决定每个数据构造是定义成类还是结构体。 按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
合适的结构体候选者包括:
在所有其它案例中,定义一个类,生成一个它的实例,并通过引用来管理和传递。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。 集合(Collection)类型的赋值和拷贝行为Swift 中 Objective-C中
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |