Swift枚举详解4

119 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情

前面说完了 Single-payload enums , 接下来我们说第三种情况 Mutil-payload enums , 有多个负载的情况产生时,当前的 enum是如何进行布局的哪?

enum ZGEnum {
    
    case test_one(Bool)
    case test_two(Bool)
    case test_three
    case test_four
    
}

print(MemoryLayout<ZGEnum>.size)
print(MemoryLayout<ZGEnum>.stride)

var a = ZGEnum.test_one(false)
var b = ZGEnum.test_two(true)
var c = ZGEnum.test_three
var d = ZGEnum.test_three
var f = ZGEnum.test_four
1
1

上面这个例子中,我们有两个 **Bool 类型**的负载,这个时候我们打印当前的 enum 大小 发现其大小仍然为 1,这个时候我们来看一下内存当中的存储情况。

image.png

这里我们可以看到当前内存存储的分别是 00 41 80 80 81 00 , 这里在存储当前的 case 时候会使用到 common spare bits,什么意思?其实在上一个案例我们也讲过了,首先 bool 类型需要 1 字节,也就是 8 位。

image.png

接下来我们来看一下 00 41 80 80 81 00 分别代表的是什么?首先 0, 4, 8 这里我们叫 做 tag value0, 1 这里我们就做**tag index**。
当前一般来说,我们有多个负载的枚举时,当前枚举类型的大小取决于当前最大关联值的大小。

递归枚举

递归枚举其实就是使用递归的方式来进行数据描述。使用**indirect**关键字修饰的枚举值表示这个枚举值是可递归的,即此枚举值中的相关值可以使用其枚举类型本身。

enum Expression {
    case num(num: Int)
    indirect case add(num1: Expression, num2: Expression)
    indirect case sub(num1: Expression, num2: Expression)
    indirect case mul(num1: Expression, num2: Expression)
    indirect case div(num1: Expression, num2: Expression)
}

使用Expression枚举来描述复合表达式 ( (5 + 5) * 2 - 8) / 2的代码如下:

///单值 5
var num5 = Expression.num(num: 5)
/// 表达式 5 + 5
var exp1 = Expression.add(num1: num5, num2: num5)
///单值 2
var num2 = Expression.num(num: 2)
///表达式 (5 + 5) * 2
var exp2 = Expression.mul(num1: exp1, num2: num2)
///单值 8
var num8 = Expression.num(num: 8)

///表达式 (5 + 5) * 2 - 8
var exp3 = Expression.sub(num1: exp2, num2: num8)

///表达式 ((5 + 5) * 2 - 8) / 2
var expFinal = Expression.div(num1: exp3, num2: num2)

我们可以为这个四则表达式枚举类型Expression实现一个函数来进行运算,在开发中将描述与运算结合,能够编写出十分优美的代码。处理递归枚举通常会采用递归函数,函数方法实现示例如下:

func expressionFunc(num: Expression) -> Int {
    switch num {
    case let .num(num):
        return num
    case let .add(num1, num2):
        return expressionFunc(num: num1) + expressionFunc(num: num2)
    case let .sub(num1, num2):
        return expressionFunc(num: num1) - expressionFunc(num: num2)
    case let .mul(num1, num2):
        return expressionFunc(num: num1) * expressionFunc(num: num2)
    case let .div(num1, num2):
        return expressionFunc(num: num1) / expressionFunc(num: num2)
        
    }
}
///((5 + 5) * 2 - 8) / 2 打印结果为6
expressionFunc(num: expFinal)

关于递归枚举还有一点需要注意,如果一个枚举中所有的枚举值都是可递归的,开发者可以直接将整个枚举类型声明为可递归的,示例如下:

indirect enum Expression {
    case num(num: Int)
    case add(num1: Expression, num2: Expression)
    case sub(num1: Expression, num2: Expression)
    case mul(num1: Expression, num2: Expression)
    case div(num1: Expression, num2: Expression)
}