一、枚举的定义
枚举是一种基本的数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。
1、定义一个枚举类型
enum Season {spring, summer, autumn, winter};
2、定义一个枚举变量
enum Season s;
3、枚举变量赋值
s = spring;
1、声明一个枚举类型,n并定义一个枚举变量
enum Season {spring, summer, autumn, winter}s;
2、枚举变量赋值
s = spring;
s = 1
二、Swift中的枚举
2.1、枚举的基本使用
enum CompassPoint {
case north
case south
case east
case west
}
var s:CompassPoint = .north
s = CompassPoint.east
switch s {
case .north:
print(“north”)
case .south:
print(“south”)
case .east:
print(“east”)
case .west:
print(“west”)
}
不像 C 和 Objective-C 那样,Swift 的枚举成员在被创建时不会分配一个默认的整数值。在上文的 CompassPoint例子中, north, south, east和 west并不代表 0, 1, 2和 3。而相反,不同的枚举成员在它们自己的权限中都是完全合格的值,并且是一个在 CompassPoint中被显式定义的类型。
2.2、关联值
有时可以将枚举的成员值跟其他类型的值关联存储在一起会非常有用
enum Score {
case point(Int)
case grade(String)
}
var score = Score.point(100)
let
switch score {
case let .point(i): print(i)
case var .grade(a): a = "20" ;print(a)
}
- 和以往一样,可以用 switch 语句来检查。这一次,总之,相关值可以被提取为 switch 语句的一部分。你提取的每一个相关值都可以作为常量(用 let前缀) 或者变量(用 var前缀)在 switch的 case中使用。
enum Date {
case digit(year:Int,month:Int)
case string(hours:String,minutes:String,seconds:String)
}
var date = Date.digit(year: 2019, month: 12)
switch date{
case .digit(let year, let moth):
print(year);
print(moth)
case let .string(hours: h, minutes: m, seconds: s):
print(h)
print(m)
print(s)
}
- 相关值都可以给定一个参数标签
- let或var可以在括号内分别修饰,也可以在括号外修饰所有
2.3 原始值
1、关联值展示了了枚举成员是如何声明它们存储不同类型的相关值的。作为相关值的另一种选择,枚举成员可以用相同类型的默认值预先填充(称为原始值)。
enum Season: Int{
case spring = 0
case summer = 1
case autumn = 2
case winter = 3
}
var s = Season.summer
let value = s.rawValue
print(value)
- 这里定义了一个叫做 Season的枚举原始值被定义为类型 Int,可以通过rawvalue属性获得原始值
enum direction: String{
case north = "north",weast = "weast",east = "east",south = “south”
}
var d = direction.east
print(d.rawValue)
- 这里定义了一个叫做direction的枚举原始值被定义为类型 String,可以通过rawvalue属性获得原始值
2、当你在操作存储整数或字符串原始值枚举的时候,你不必显式地给每一个成员都分配一个原始值。当你没有分配时,Swift 将会自动为你分配值。
enum Season: Int{
case spring
case summer
case autumn
case winter
}
var s = Season.summer
let value = s.rawValue
print(value)
enum direction: String{
case north ,weast,east,south
}
var d = direction.east
print(d.rawValue)
- 只要定义了枚举原始值的存储对象是整数或字符串,系统就会隐式的为每一个成员提供一个原始值。
3、从原始值初始化
enum Season: Int{
case spring
case summer
case autumn
case winter
}
let s = Season(rawValue: 3)
let s1 = Season(rawValue: 6)
let v = s?.rawValue
let v1 = s1?.rawValue
if let value = v {
print(value)
}
if v1 == nil {
print("没有原始值为的变量”)
}
- 我们可以用一个能接受原始值类型的值的初始化器来创建一个枚举的新实例。
2.4、枚举变量的内存
2.4.1 一般枚举
enum Season {
case spring
case summer
case autumn
case winter
}
var s = Season.spring
MemoryLayout.stride(ofValue: s) 1,分配占用的空间大小
MemoryLayout.size(ofValue: s) 1,实际用到的空间大小
MemoryLayout.alignment(ofValue: s) 1,对齐参数
- 枚举变量s (0x0000000100006568)在内存中只占用一个字节的内存大小
enum Season {
case spring
case summer
case autumn
case winter
}
var s = Season.spring
s = Season.summer
s = Season.autumn
s = Season.winter
print(“fff”)
var s = Season.spring
系统枚举变量s 分配了一个字节,存储着0
截屏2019-11-30下午8.37.51.png
s = Season.summer
系统给枚举变量s 分配了一个字节,存储着1
截屏2019-11-30下午8.38.24.png
s = Season.autumn
系统给枚举变量s 分配了一个字节,存储着2
截屏2019-11-30下午8.39.15.png
s = Season.winter
系统给枚举变量s 分配了一个字节,存储着3
截屏2019-11-30下午8.39.43.png
- 普通的枚举变量只占一个字节,用来存储枚举的一个成员变量,用来区分当前是哪个表示枚举成员。
2.4.2 关联值
1、打印变量的字节
enum Test1 {
case number(Int,Int,Int,Int)
case summer
}
print(MemoryLayout<Test1>.size) 33,实际用到的空间大小
print(MemoryLayout<Test1>.stride) 40,分配占用的空间大小
print(MemoryLayout<Test1>.alignment) 8,对齐参数
- 系统给枚举变量分配40个字节,实际占用了33个字节
enum Test2 {
case number(Int)
case summerr(Int,Int)
}
print(MemoryLayout<Test2>.size) 17,实际用到的空间大小
print(MemoryLayout<Test2>.stride) 24,分配占用的空间大小
print(MemoryLayout<Test2>.alignment) 8,对齐参数
- 系统给枚举变量分配24个字节,实际占用了17个字节
enum Test3 {
case number
case summerr(Int,Int)
}
print(MemoryLayout<Test3>.size) 17,实际用到的空间大小
print(MemoryLayout<Test3>.stride) 24,分配占用的空间大小
print(MemoryLayout<Test3>.alignment) 8,对齐参数
- 系统给枚举变量分配24个字节,实际占用了17个字节
enum Test4 {
case summerr(Int,Int)
case winter(Int,Int,Int)
}
print(MemoryLayout<Test4>.size) 25,实际用到的空间大小
print(MemoryLayout<Test4>.stride) 32,分配占用的空间大小
print(MemoryLayout<Test4>.alignment) 8,对齐参数
- 系统给枚举变量分配32个字节,实际占用了25个字节
2、实例分析
2.1
enum Test1 {
case summer
case number(Int,Int,Int,Int)
}
var t = Test1.number(1,2, 3, 5)
01 00 00 00 00 00 00 00 存储1
02 00 00 00 00 00 00 00 存储2
03 00 00 00 00 00 00 00 存储3
05 00 00 00 00 00 00 00 存储5
00 存储枚举成员
t = .summer
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
01
- 系统给枚举变量分配40个字节,实际占用了33个字节。其中前32个字节用来存储关联值,一个字节用来存储枚举的成员值用来区分当前是哪个表示枚举成员。
2.2
enum Test2 {
case number(Int)
case summerr(Int,Int)
}
var t = Test2.number(10)
0A 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00
t = .summerr(1, 2)
01 00 00 00 00 00 00 00
02 00 00 00 00 00 00 00
01
- 系统给枚举变量分配24个字节,实际占用了17个字节。其中前16个字节用来存储关联值,一个字节用来存储枚举的成员值用来区分当前是哪个表示枚举成员。
2.3
enum Test3 {
case number
case summerr(Int,Int)
}
var t = Test3.number
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
01
t = .summerr(1, 2)
01 00 00 00 00 00 00 00
02 00 00 00 00 00 00 00
00
- 系统给枚举变量分配24个字节,实际占用了17个字节。其中前16个字节用来存储关联值,一个字节用来存储枚举的成员值用来区分当前是哪个表示枚举成员。
2.4
enum Test4 {
case summerr(Int,Int)
case winter(Int,Int,Int)
}
var t = Test4.summerr(10, 20)
0A 00 00 00 00 00 00 00
14 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00
�
t = .winter(1, 2, 3)
01 00 00 00 00 00 00 00
02 00 00 00 00 00 00 00
03 00 00 00 00 00 00 00
01
�
- 系统给枚举变量分配32个字节,实际占用了25个字节。其中前24个字节用来存储关联值,一个字节用来存储枚举的成员值用来区分当前是哪个表示枚举成员。
2.5
enum Test5 {
case summer
}
var t1 = Test5.summer
print(MemoryLayout.stride(ofValue: t1)) 1
print(MemoryLayout.size(ofValue: t1)) 0
print(MemoryLayout.alignment(ofValue: t1)) 1
- 枚举只有一个case不需要去区分枚举成员,因此编译器就不给枚举变量分配内存
2.6
enum Test5 {
case summer(Int)
}
var t1 = Test5.summer(8)
print(MemoryLayout.stride(ofValue: t1)) 8
print(MemoryLayout.size(ofValue: t1)) 8
print(MemoryLayout.alignment(ofValue: t1)) 8
- 枚举只有一个case不需要去区分枚举成员,但需要用8个字节去存储关联值,因此枚举变量就实际占用8个字节
2.7
enum Test5 {
case summer,winter
}
var t1 = Test5.summer
print(MemoryLayout.stride(ofValue: t1)) 1
print(MemoryLayout.size(ofValue: t1)) 1
print(MemoryLayout.alignment(ofValue: t1)) 1
- 枚举有多个case,需要用一个字节去区分枚举成员,因此枚举变量会实际占用一个字节。
- 1个字节存储原始值
- n个字节存储关联值(n取占用最大内存的关联值),任何一个case的关联值都共用这n个字节
- 关联值:有时候将枚举的成员值跟其他类型的值关联存储在一起
2.4.3 原始值
enum Season: Int{
case spring
case summer
case autumn
}
var s = Season.spring
print(MemoryLayout.stride(ofValue: s)) 1
print(MemoryLayout.size(ofValue: s)) 1
print(MemoryLayout.alignment(ofValue: s)) 1
enum direction: String{
case north = "north",weast = "weast",east = "east",south = "south"
}
var d = direction.east
print(MemoryLayout.stride(ofValue: d)) 1
print(MemoryLayout.size(ofValue: d)) 1
print(MemoryLayout.alignment(ofValue: d)) 1
-
原始值不占枚举变量的内存空间,内存布局和一般枚举一样。至于原始值存储到哪里,我们可以假如原始值的获得是在通过一个函数。
-
原始值和关联值的本质区别就在于,关联值会占用枚举变量的内存,而原始值不会占用枚举变量的内存
网友评论