能否将带关联值的枚举模式存储在数组中?
当然可以实现!不过带关联值的枚举和你原来的简单枚举逻辑不一样——每个带关联值的枚举实例都是具体的实例(比如.audio(duration: 10)和.audio(duration: 20)是完全不同的实例),没法直接把「匹配模式」(比如“所有音频类型”“时长超过10秒的音频”)存进数组里。我们可以换个思路,通过闭包或者自定义匹配类型来搞定这个需求。
先改造你的枚举(添加关联值)
首先把原来的简单枚举改成带关联值的版本:
import CoreGraphics enum MessageType { case audio(duration: TimeInterval) case photo(resolution: CGSize) case text(content: String) }
方案一:用闭包数组封装匹配逻辑
我们可以把「是否能处理」的判断逻辑封装成闭包,存进Handler的数组里,这样既能匹配任意case类型,也能匹配带特定关联值条件的消息:
class Handler { private let matchers: [(MessageType) -> Bool] // 基础构造方法:直接传入匹配闭包数组 init(matchers: [(MessageType) -> Bool]) { self.matchers = matchers } // 便捷构造方法:匹配任意指定的case类型(忽略关联值) convenience init(allowedCases: [MessageType]) { let matchers = allowedCases.map { targetCase in return { message in // 通过模式匹配判断是否属于同一case(不管关联值) switch (message, targetCase) { case (.audio, .audio): return true case (.photo, .photo): return true case (.text, .text): return true default: return false } } } self.init(matchers: matchers) } func canHandle(_ message: MessageType) -> Bool { // 只要有一个闭包返回true,就说明能处理 return matchers.contains { $0(message) } } }
用法示例
- 匹配任意音频和照片类型(忽略关联值)
// 这里传入的关联值只是占位,我们只关心case类型 let basicHandler = Handler(allowedCases: [.audio(duration: 0), .photo(resolution: .zero)]) print(basicHandler.canHandle(.audio(duration: 15))) // 输出 true print(basicHandler.canHandle(.text(content: "Hello World"))) // 输出 false
- 匹配带特定条件的消息(比如时长>10秒的音频)
let customHandler = Handler(matchers: [ // 匹配时长超过10秒的音频 { message in if case .audio(let duration) = message, duration > 10 { return true } return false }, // 匹配包含"紧急"关键词的文本消息 { message in if case .text(let content) = message, content.contains("紧急") { return true } return false } ]) print(customHandler.canHandle(.audio(duration: 12))) // 输出 true print(customHandler.canHandle(.text(content: "紧急通知:系统维护"))) // 输出 true print(customHandler.canHandle(.photo(resolution: CGSize(width: 100, height: 100)))) // 输出 false
方案二:自定义模式枚举(更清晰易读)
如果觉得闭包不够直观,我们可以专门定义一个MessagePattern枚举,用来表示各种匹配模式,代码可读性会更好:
enum MessagePattern { // 匹配任意对应类型的消息 case anyAudio case anyPhoto case anyText // 匹配带特定条件的消息 case audioWithMinDuration(TimeInterval) case photoWithMinResolution(width: CGFloat, height: CGFloat) case textContaining(String) // 判断当前模式是否匹配某条消息 func matches(_ message: MessageType) -> Bool { switch (self, message) { case (.anyAudio, .audio): return true case (.anyPhoto, .photo): return true case (.anyText, .text): return true case (.audioWithMinDuration(let min), .audio(let duration)): return duration >= min case (.photoWithMinResolution(let minW, let minH), .photo(let res)): return res.width >= minW && res.height >= minH case (.textContaining(let substr), .text(let content)): return content.contains(substr) default: return false } } } class Handler { private let patterns: [MessagePattern] init(patterns: [MessagePattern]) { self.patterns = patterns } func canHandle(_ message: MessageType) -> Bool { return patterns.contains { $0.matches(message) } } }
用法示例
let patternHandler = Handler(patterns: [ .audioWithMinDuration(10), .textContaining("urgent") ]) print(patternHandler.canHandle(.audio(duration: 15))) // 输出 true print(patternHandler.canHandle(.text(content: "Urgent action required!"))) // 输出 true print(patternHandler.canHandle(.photo(resolution: CGSize(width: 1920, height: 1080)))) // 输出 false
总结
带关联值的枚举不能直接把「模式」存进数组,但我们可以通过闭包封装匹配逻辑或者自定义模式枚举的方式,实现更灵活的消息处理判断。两种方案各有优劣:闭包更灵活,适合快速实现复杂逻辑;自定义模式枚举可读性更强,适合团队协作和长期维护。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

