浅学Swift 3.0.1中的Classes and structures

来源:互联网 发布:大数据公司怎么盈利 编辑:程序博客网 时间:2024/06/05 19:33


序言

类和结构体是那些构建程序代码块的用途广并且灵活的构造器, 你可以通过使用像对常量、变量、和函数完全相同的语法来定义属性和方法, 从而来扩展类和结构体的功能。不像其他编程语言, Swift不要求你为自定义的类和结构体创建单独的声明和实现文件。在Swift中, 你可以定义在同一个文件中定义一个类或结构体, 并且那个类和结构体的额外声明自动对其他代码的使用是可以用的。

注意:类实例在传统上是作为一个对象, 然而,相对其他语言来说, Swift中的类和结构体更接近于函数。



本章目录

  • 类和结构体的比较
  • 定义语法
  • 获取属性
  • 结构体类型的逐一成员构造器
  • 结构体和枚举是值类型
  • 类是引用类型
  • 恒等操作符
  • 在类和结构体之间选择
  • 字符串、数组、字典的赋值和拷贝行为



类和结构体的比较

在swift中, 类和结构体有很多共同之处, 两者都能:

  • 定义存储值的属性
  • 定义提供功能的方法
  • 定义下标来提供获取到它们使用下标语法的值
  • 定义建立初始状态的初始化器
  • 通过扩展,在默认实现外扩展它们的功能
  • 遵循提供某个类的标准功能的协议

还有着结构体没有的能力:

  • 继承使一个类能够继承另一个类的特征
  • 类型转换使你能够在运行时检查和解释一个类实例的类型
  • 析构器使类实例能够释放任何它所分配的资源
  • 引用计数允许对一个类实例的多次引用

注意:结构体是值类型, 所以结构体在代码中传递并且不使用引用计数的时候, 结构体总是被复制。



定义语法

类名和结构体名首字母要大写,形式:

class MyClass {    // 类定义在这儿}struct MyStructure {    // 结构体定义在这儿}// 这个结构体有两个存储属性struct Resolution {    var width = 0    var height = 0}class VideoMode {    // resolution被初始化成一个新的Resolution结构体实例    var resolution = Resolution()    var interlaced = false    var frameRate = 0.0    var name: String?}// 创建一个结构体实例let someResolution = Resolution()// 创建一个类实例let someVideoMode = VideoMode()



获取属性

你可以使用点语法获取实例属性:

// 通过点语法获取方式:(实例.属性)someResolution.width = 1someVideoMode.interlaced = truesomevideoMode.resolution.height = 100



结构体类型的逐一成员构造器

所有结构体都有一个自动生成的逐一成员构造器, 你能使用其来初始化新的结构体实例的成员属性, 新实例的属性的初始化值能通过名字传递给逐一成员构造器。

let newStructureInstance = Resolution(width: 1, height: 2)

和结构体不一样, 类实例没有接收一个默认逐一成员构造器, 也就是说, 类没有默认的逐一成员构造器。



结构体和枚举是值类型

值类型是一个当它被赋值给一个常量或变量, 或传递给函数的时候其值被复制的类型。

在swift中, 所有的基本类型—整型int, 浮点数floating-point, 布尔值Booleans, 字符串strings, 数组arrays和字典dictionaries都是值类型。

在swift中, 所有结构体和枚举都是值类型, 这就意味着任何你创建的结构体和枚举实例–并且任何作为属性的值类型–当在代码中传递时总是被复制。

 // valueType是一个Resolution实例 let valueType = Resolution(width: 11, height: 22) // 变量cinema也是一个Resolution实例 var cinema = valueType

在上面例子中,valueType和cinema有同样的width和height, 但是他们是两个完全不同的实例。
下面给cinema.width赋值:

 // 给cinema.width赋值12 cinema.width = 12 // 打印结果:12 print(cinema.width) 

然而, cinema的属性width已经改变成12, 但是原来的值依然是11(valueType.width), 也即是说设置cinema.width并不影响存储在valueType中的width。

同样, 也可以用到枚举中:

enum CompassPoint {    case north, south, east, west}var currentDirection = CompassPoint.westlet rememberedDirection = currentDirectioncurrentDirection = .eastif rememberedDirection == .west {    print("rememberedDirection is still .west, has not any changes!")}// 打印结果:rememberedDirection is still .west, has not any changes!



类是引用类型

和值类型不一样, 引用类型不能被复制当被赋值给一个常量或变量的时候, 或者当传递给函数的时候。引用类型直接被替换, 不会copy!

let hd = Resolution(width: 111, height: 222)let tenEightly = VideoMode()tenEightly.resolution = hdtenEightly.interlaced = truetenEightly.name = "1080i"tenEightly.frameRate = 25.0let alsoTenEight = tenEightlyalsoTenEight.frameRate = 30.0// 打印结果:30.0print(tenEightly.frameRate)

从上面这个例子可以明显地看出, 尽管我们将常量tenEightly赋值给常量alsoTenEight, 当给alsoTenEight的frameRate赋值的时候, tenEightly的frameRate也跟着变了, 这是因为tenEightly和alsoTenEight都是指向同一个VideoMode实例, 所以本质上是对VideoMode实例的改变。



恒等操作符

因为类是引用类型, 所以多个常量和变量在幕后访问/引用同一个类实例是可能的。(结构体和枚举就不行,因为当赋值常量或变量或者传递给函数的时候, 它们总是被拷贝!)

有时, 弄清楚两个常量或变量是否完全引用同一个类实例是有用的。对此, Swift提供了两个恒等操作符:

  • 恒等于(===)
  • 非恒等于(!==)

使用这些操作符来检查两个常量或变量是否访问同一个实例。

class VideoMode {    var frameRate = 0.0}let videoModeInstance = VideoMode()videoModeInstance.frameRate = 12.7let alsoVideModeInstance = videoModeInstancealsoVideModeInstance.frameRate = 44.3if videoModeInstance === alsoVideModeInstance {    print("videoModeInstance and alsoVideoModeInstance refer to the same VideoMode instance")}

如上面, videoModeInstance和alsoVideoModeInstance可以用恒等式来判断它们是否引用同一个实例。

注意: “===”和“==”是不同的

  • “===”恒等于意味着类类型的两个常量或变量引用完全一样的类实例
  • “==”等于意味着两个实例在方面是否相等

在C,C++, OC中, 这些语言使用指针来指向内存中的地址。在swift中, 一个指向某个引用类型实例的常量或变量与C中的指针类似, 但是并不是直接指向内存中的地址的指针并且也不要求你写 “*” 来表明你在创建一个引用, 在swift中, 这些引用被定义像其他常量或变量一样。



在类和结构体之间选择

结构体实例总是通过传递, 类实例总是通过引用传递。

作为一个参考, 当这些条件中有一个或多个被应用到时, 考虑创建结构体:

  • 该结构的主要目的是封装少量相对简单的数据值
  • 当赋值或传递那个结构的实例时,希望被封装的值是被复制而不是引用
  • 该结构存储的任何值本身就是值类型, 这也期望被赋值而不是引用
  • 该结构不需要从另一个存在类型继承属性或行为

好的结构体候选例子包括:

  • 几何形状的大小, 或许要封装一个 width 属性和 height 属性, 两个 Double 类型
  • 一种引用序列范围的方法, 或许要封装一个 start 属性和一个 length 属性, 两个 Int 类型
  • 一个3D坐标系统的点, 或许要封装 x, y和z, 每个类型都是Double

在所有其他情况中, 定义类, 创建那个类的实例通过引用来管理或传递。实际上, 这就意味着大多数自定义数据构造应该是类, 而不是结构体!



字符串、数组、字典的赋值和拷贝行为

在swift中, 像String, Array, Dictionary等很多基本数据类型都是用结构体来实现,这意味着当它们被赋值到一个新的常量或变量的时候, 或者当被传递给一个函数或方法的时候, 他们的值会被拷贝。 这和Foundation不同:NSString, NSArray,和NSDictionary被作为类而不是结构体来实现, 它们总是作为一个存在实例的引用来赋值和传递, 而不是作为拷贝来赋值和传递。


注意:上面是对字符串、数组和字典的描述, 拷贝行为在你的代码中好像总是会发生。然而, swift只有在绝对必要时会执行实际的拷贝。swift会管理所有的值拷贝来确保最优化执行, 你不需要避免赋值来保证性能的最优化。




本文来自Swift3.0.1官方英文版, 作者自译, 欢迎学习, 禁止用于商业用途, 侵权必究! 由于个人能力有限, 欢迎指出其中不足之处!

0 0