如何引用协议的associatedtype?Swift关联类型使用疑问
解决Swift中关联类型协议的枚举映射数组问题
你想要实现的是将遵循带关联类型协议的枚举类型(或实例)映射到其对应关联类型的数组,原写法的问题在于:
T.associatedtype不是合法的Swift语法,无法直接引用关联类型;- 泛型结构体
MyStruct<T: MyProtocol>中的T只能代表单一遵循协议的类型,无法同时容纳多种不同的枚举类型作为key。
可行解决方案:类型安全的通用映射容器
我们可以通过一个内部用Any存储、外部提供泛型存取方法的结构体,实现类型安全的映射:
protocol MyProtocol { associatedtype T func foo() -> T } enum MyEnum1: MyProtocol { func foo() -> Int { return 0 } } enum MyEnum2: MyProtocol { func foo() -> String { return "" } } struct TypeMap { private var storage: [ObjectIdentifier: Any] = [:] // 向指定枚举类型的数组添加元素 mutating func append<Key: MyProtocol>(_ value: Key.T, for type: Key.Type) { let typeID = ObjectIdentifier(type) if var array = storage[typeID] as? [Key.T] { array.append(value) storage[typeID] = array } else { storage[typeID] = [value] } } // 获取指定枚举类型对应的关联类型数组 func array<Key: MyProtocol>(for type: Key.Type) -> [Key.T]? { let typeID = ObjectIdentifier(type) return storage[typeID] as? [Key.T] } }
使用示例
var map = TypeMap() // 向MyEnum1对应的Int数组添加元素 map.append(123, for: MyEnum1.self) map.append(456, for: MyEnum1.self) // 向MyEnum2对应的String数组添加元素 map.append("Hello", for: MyEnum2.self) map.append("Swift", for: MyEnum2.self) // 获取数组 print(map.array(for: MyEnum1.self)) // 输出:Optional([123, 456]) print(map.array(for: MyEnum2.self)) // 输出:Optional(["Hello", "Swift"])
如果需要以枚举实例为key
如果你希望字典的key是枚举实例而非枚举类型,可以稍作调整:
struct InstanceMap { private var storage: [ObjectIdentifier: Any] = [:] mutating func append<Key: MyProtocol>(_ value: Key.T, for instance: Key) { let typeID = ObjectIdentifier(type(of: instance)) if var array = storage[typeID] as? [Key.T] { array.append(value) storage[typeID] = array } else { storage[typeID] = [value] } } func array<Key: MyProtocol>(for instance: Key) -> [Key.T]? { let typeID = ObjectIdentifier(type(of: instance)) return storage[typeID] as? [Key.T] } }
使用时:
var instanceMap = InstanceMap() let enum1Instance = MyEnum1() let enum2Instance = MyEnum2() instanceMap.append(789, for: enum1Instance) instanceMap.append("World", for: enum2Instance) print(instanceMap.array(for: enum1Instance)) // 输出:Optional([789])
这种方案通过ObjectIdentifier标识不同的枚举类型,内部用Any存储数组,再通过泛型方法保证存取时的类型安全,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者WongWray
相关产品推荐
相关产品推荐

