带关联值的枚举

发布
更新
字数 503
阅读 3 分钟
阅读量 1123

带关联值的枚举,可以使其成员携带更多信息。参考官方文档:https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations/#Associated-Values

关联值的获取与比较

主要有两种方式。switch case 模式可以遍历全部成员并作出回应,如果只对一个或部分成员感兴趣,可以使用 if case 语句赋值比较。

enum Item {
    case text(String)
}

let textA: Item = .text("a")

// 也可以写成
if case let .text(a) = textA {
    print(a)
}

修改关联值

如果需要修改枚举值的关联值,我们可以为其增加一个 mutating 函数

extension Item {
    mutating func append(_ aString: String) {
        switch self {
        case .text(let string):
            self = .text(string.appending(aString))
        }
    }
}

Hashable

Hashable enumeration 在 diffable data source 中使用非常方便。上例中,枚举关联值类型为 String 是 hashable 的,所以只需要扩展一个协议即可

extension Item: Hashable {}

如果关联值不全是 Hashable 类型,需要手动实现相应的方法

enum ActionItem {
    typealias Action = () -> Void

    case text(String, action: Action)
}

extension ActionItem: Hashable {
    static func == (lhs: ActionItem, rhs: ActionItem) -> Bool {
        // 比较主要关联值
		if case let .text(lString, _) = lhs, case let .text(rString, _) = rhs {
            return lString == rString
        }
        
        return false
    }

    // `hash(into:)` 方法与 `==` 方法关注的值是一样的
    func hash(into hasher: inout Hasher) {
        switch self {
        case let .text(string, _):
            hasher.combine(string)
        }
    }
}

其他

我们还可以为 ActionItem 添加一个便利方法

extension ActionItem {
    func excute() {
        // 注意这里获取关联值时,把 `let` 放在了括号里面也是可以的,
        // 与 `switch` 一样支持两种写法
        if case .text(_, let action) = self {
            action()
        }
    }
}

在上面比较两个枚举值是否相等时用到了 if case let .text(lString, _) = lhs, case let .text(rString, _) = rhs 获取关联值,我们也可以添加一个计算属性

extension ActionItem {
    var associatedValue: String {
        switch self {       
        case .text(let string):
            return string
        }
    }
}

//...

// 然后

//...
static func == (lhs: ActionItem, rhs: ActionItem) -> Bool {
    // 这里省略了 `return`
    lhs.associatedValue == rhs.associatedValue
}