【Swift学习】Enum、Struct、Class的学习及异同
来源:互联网 发布:office for mac 激活 编辑:程序博客网 时间:2024/05/18 02:15
Swift初学者,刚过完一遍Swift Apprentice,期间配合着《Swift 3.0官方教程中文版》看,对于几个比较重要又较为复杂的知识点,通过查查资料,写写博客的方式系统化知识并加深理解。
enum、struct、class都是Swift提供的“named types”(protocol将单独介绍),它们之间有很多相同之处,又有各自的特性,存在即合理,在正确的时刻选择正确的“named types”算是初学者的必修课了吧,下面将从最基础的语法讲起,同时介绍各自的特性以及异同。
枚举(Enumerations)
定义:枚举为一组相关的值定义了一个共同的类型,使你可以以类型安全的方式来使用这些值
枚举的语法
enum CompassPoint { case north case south case east case west}用enum关键字来表示枚举,大括号中用case关键字来定义新的枚举成员值。
Swift也提供了更简洁的语言,省略多余的case,将多个成员值用逗号隔开,如下:
enum CompassPoint { case north, south, east, west}
实例的创建及使用:
//将枚举中的某个值赋值给变量var compassPoint = CompassPoint.north//当系统已经知道变量的枚举类型时,可以省略类型名compassPoint = .south
原始值(Raw values)
枚举的成员可以被默认值(原始值)预填充,这些原始值的类型必须相同。
定义一个原始值为Int的枚举类型Month。
enum Month: Int { case january , february, march, april, may, june, july, august, september, october, november, december}
var month = Month.januarymonth.rawValue //0,调用rawValue显示原始值,未设置原始值默认为0//修改Month枚举如下enum Month: Int { case january = 1 , february, march, april, may, june, july, august, september, october, november, december}month.rawValue //此时january = 1month = .aprilmonth.rawValue // 4, 系统隐式赋值
当原始值的类型为String类型时,每个枚举成员的隐式原始值是该成员的名称,继续修改之前的CompassPoint:
enum CompassPoint: String { case north, south, east, west}let compassPoint = CompassPoint.north.rawValue // "north"
使用原始值初始化变量或常量:
let fourMonth = Month(rawValue:4) //april, fourMonth为Month?类型,是可选的,因为//并非所有的rawValue都有对应的成员值,若匹配不到时将赋值为nil
关联值(Associated values)
1. 每一个枚举成员可有以一个或多个关联值
2. 每个枚举成员的关联值可以是不同的数据类型
3. 定义关联值与函数的参数类似
直接来看例子吧,以Swift官方教程为例:
一个商品可以有两种不同的条形码来跟踪商品,分别是UPC格式的一维条形码,用数字表示,另一种是DR码格式的二维码,用字符串表示,于是定义如下枚举类型:
enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String)}我们可以看到,Barcode枚举类型有两个成员值upc、qrCode,其中upc具有元组类型的(Int, Int, Int, Int)关联值,qrCode具有String类型关联值。
而当枚举成员有了关联值之后,就不能再有原始值了,即关联值与原始值不能同时存在。
var barcode = Barcode.upc(8,85909, 51226, 3) //创建了一个变量,并赋值为Barcode.upcbarcode = .qrCode("ABCDEFGHIJQ") //此时barcode已经是Barcode类型,因此我们可以省略//枚举类型名,barcode被赋值为一个不同类型的条形码barcode可以存储一个.upc或者.qrCode类型的值,但是同一时间只能存储其中的一个。这也是enum与接下来要讲的struct和class的一个区别:当一个变量或常量被声明为一个枚举类型,它只能是枚举类型中的某一个成员值,而一个变量被声明为struct或class时,包含了其中所含有的所有属性(properties)和方法(methods)。
因此,什么时候应该使用enum呢,让我们重新看看枚举的定义:为一组相关的值定义了一个共同的类型,使你可以以类型安全的方式来使用这些值。
即当要使用一组相关的值的时候,如上述例子中的月份(january, february, may ...),我们就可以为这组相关的值定义一个枚举类型。
结构体(Structures) & 类(Classes)
结构体与类在语法等方面非常相似,因此这部分的介绍就整合在一起,也更加方便对比,下文会更详细地介绍它们的不同之处。
类和结构体定义语法
struct Location { let x: Double let y: Double func distance() -> Double { return sqrt((x * x) + (y * y)) }}class Person { var firstName: String var lastName: String init(firstName: String, lastName: String){ self.firstName = firstName self.lastName = lastName } func fullName() -> String{ return "\(firstName) \(lastName)" }}
此处分别定义了一个Location结构体以及一个Person类,可以看到它们除了关键字的差别,其他的定义方式基本是一样的。结构体和类都可以有属性和方法。
构造器(initializers)
可以看到上文代码比较明显的差别就是:class含有一个init(_:_:)方法,而struct没有。因为所有结构体会自动生成一个成员逐一构造器,用于初始化新结构体实例中的成员属性,因此我们可以直接声明一个实例并设置其各个属性的初始值:
let location = Location(x: 2, y: 4)
而类是没有默认的成员逐一构造器的,因此,若删除class中的init(_:_:)方法,Xcode将会报错:"Class
Person has no initailizers",即Person类中没有构造器。因此我们在创建类的时候,必须创建一个及以上的构造器。
当然我们也可以对构造器进行重载(overload),系统将会根据参数的类型和数据自动地调用对应的构造器。当在结构体中手动添加了init(_:_:)方法后,默认的成员逐一构造器将会失效。
以结构体Location为例,我们可以之前的代码中加入多个构造器:
struct Location { let x: Double let y: Double func distance() -> Double { return sqrt((x * x) + (y * y)) } //构造器1 init(x: Double, y: Double) { self.x = x self.y = y } //构造器2 init(x: Double ) { self.x = x self.y = 0 } //构造器3 init() { x = 0 y = 0 }}//创建实例并调用let location1 = Location(x: 2, y: 4) //此时系统将会自动调用我们定义的构造器1 init(_:_:)print(location1) //Location(x: 2.0, y: 4.0)let location2 = Location(x: 2) //此时系统将调用构造器2 init(_:)print(location2) //Location(x: 2.0, y: 0.0)let location3 = Location() //此时系统调用无参构造器3 init()print(location3) //Location(x: 0.0, y: 0.0)
访问(Accessing)
结构体实例(instance)的创建的语法已经在上文出现过了,类实例的创建也是一样:
let john = Person(firstName: "Johnny", lastName:"Appleseed")
有了实例之后我们就可以访问结构体和类中的成员属性和方法:
john.firstName //"Johnny", 访问属性firstNamejohn.fullName() //"Johnny Appleseed", 访问方法fullName(_:_:)
结构体与类的异同及使用场景
以上只介绍了结构体和类简单的定义及使用,类还有一个很重要的功能:继承(inheriance),但这里就不展开细讲了。接下来就对结构体和类做一个比较:
类和结构体的异同
类和结构体有很多共同点。共同处在于:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义下标操作使得可以通过下标语法来访问实例所包含的值
- 定义构造器用于生成初始化值
- 通过扩展以增加默认实现的功能
- 实现协议以提供某种标准功能
与结构体相比,类还有如下的附加功能:
- 继承
- 类型转换:运行时检查和解释一个类实例的类型
- 析构器:释放一个实例的所有资源
- 引用计数
类和结构体在内存中的实现机制的不同:
- 类存储在堆(heap)中,结构体存储在栈(stack)中
- 类是引用类型,而结构体是值类型
实现机制的不同是我们判断使用类还是结构体的一个很重要的依据,这块比较复杂,将会在下一篇博客中详细描述。
类和结构体的使用场景
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
- 该数据结构的主要用来封装少量相关简单数据值。
- 希望数据结构的实例被赋值给另一个实例时是拷贝而不是引用,封装的数据及其中存储的值也是拷贝而不是引用
- 该数据结构不需要使用继承
举例来说,以下情境中适合使用结构体:
- 几何形状的大小,封装一个 width 属性和 height 属性,两者均为 Double 类型。
- 三维坐标系内一点,封装 x , y 和 z 属性,三者均为 Double 类型。
以上,就是enum、struct、class的入门学习,有任何不对的地方欢迎大家指正。
- 【Swift学习】Enum、Struct、Class的学习及异同
- Swift学习 enum的遍历
- struct 和 class的异同?
- class和struct 的异同
- struct和class的异同
- class与struct的异同
- C++11的enum class & enum struct和enum
- C++中struct与class的异同
- c学习的基本问题-4:关于struct,union,enum
- swift简单学习之Struct
- Swift 学习笔记 class
- C#中struct和enum学习分享
- Swift 之别具一格的 Struct 和 Class
- Swift - Struct 與 Class 的差異性
- Swift - Struct 与Class 的差异性
- swift中class和struct的区别
- [IOS] Swift enum and Struct
- class,struct与union异同
- 深入理解浮点数类型float和double
- hsweb 企业后台管理 登录超时退出
- nginx echo 输出 检查配置正确性
- 【链表】复杂链表的复制
- 美团API使用之外卖订单
- 【Swift学习】Enum、Struct、Class的学习及异同
- 第四题
- ListView添加自定义适配器最优方案
- java项目通过设置JVM属性参数依赖本地配置
- Tensorflow中Graph的概念
- MooseFS3.0分布式文件系统安装升级手记【迁移02】
- iOS开发 使用NSURLConnection实现图片上传
- shiro注解@RequiresPermissions多权限任选一参数用法
- PAT (Advanced Level) Practise 1049 Counting Ones (30)