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

Swift 5.7中any Stuff无法遵循Hashable协议的问题求助

问题:Swift 5.7中如何让any Stuff符合Hashable以实现异构Set?

我尝试用Swift 5.7的新特性实现异构Set,简化后的Playground代码如下:

protocol Stuff: Hashable {
    var identifier: String { get }
}

struct StuffA: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

struct StuffB: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

var arrayOfStuff: Array<any Stuff> = []
arrayOfStuff.append(StuffA(identifier: "a"))
arrayOfStuff.append(StuffB(identifier: "b"))
// 运行正常

var setOfStuff: Set<any Stuff> = Set() 
// 错误:Type 'any Stuff' cannot conform to 'Hashable'
setOfStuff.insert(StuffA(identifier: "a"))
setOfStuff.insert(StuffB(identifier: "b"))

Array<any Stuff>可以正常运行,但声明Set<any Stuff>时编译器报错,无法识别any Stuff符合Hashable。已知Stuff协议继承自Hashable而非直接遵循,请问如何解决这个问题?


解决方案

方法1:在协议中显式声明Hashable核心方法

虽然Stuff继承自Hashable,但对于存在类型any Stuff,编译器需要明确的相等性判断和哈希计算逻辑。在Stuff协议中显式声明Hashable的两个核心方法,确保所有遵循类型实现统一的判断规则:

protocol Stuff: Hashable {
    var identifier: String { get }
    static func == (lhs: Self, rhs: Self) -> Bool
    func hash(into hasher: inout Hasher)
}

struct StuffA: Stuff {
    let identifier: String
    
    static func == (lhs: StuffA, rhs: StuffA) -> Bool {
        lhs.identifier == rhs.identifier
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

struct StuffB: Stuff {
    let identifier: String
    
    static func == (lhs: StuffB, rhs: StuffB) -> Bool {
        lhs.identifier == rhs.identifier
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

// 现在可正常声明并使用异构Set
var setOfStuff: Set<any Stuff> = []
setOfStuff.insert(StuffA(identifier: "a"))
setOfStuff.insert(StuffB(identifier: "b"))

方法2:使用类型擦除包装器

如果不想修改原协议,可创建一个类型擦除的结构体,将any Stuff包装为具体的Hashable类型:

protocol Stuff: Hashable {
    var identifier: String { get }
}

struct StuffA: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

struct StuffB: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

// 类型擦除包装器
struct AnyStuff: Hashable {
    private let base: any Stuff
    
    init(_ base: any Stuff) {
        self.base = base
    }
    
    static func == (lhs: AnyStuff, rhs: AnyStuff) -> Bool {
        lhs.base.identifier == rhs.base.identifier
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(base.identifier)
    }
}

// 通过包装器创建并使用Set
var setOfStuff: Set<AnyStuff> = []
setOfStuff.insert(AnyStuff(StuffA(identifier: "a")))
setOfStuff.insert(AnyStuff(StuffB(identifier: "b")))

原理说明

Swift的存在类型any Protocol对于带有关联类型或需要具体实现的协议(如Hashable),无法自动推导其一致性。因为Hashable的相等性判断依赖明确的类型信息,而any Stuff可以是任意遵循Stuff的类型,必须显式提供统一的哈希和相等性逻辑,编译器才能认可其符合Hashable约束。


内容的提问来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:20:59