You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何引用协议的associatedtype?Swift关联类型使用疑问

解决Swift中关联类型协议的枚举映射数组问题

你想要实现的是将遵循带关联类型协议的枚举类型(或实例)映射到其对应关联类型的数组,原写法的问题在于:

  1. T.associatedtype不是合法的Swift语法,无法直接引用关联类型;
  2. 泛型结构体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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:05:01