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

为何Swift中类AddIndexPublisher用Self.Failure报错,结构体则正常?

Swift中类与结构体使用Self关联类型的差异问题

问题现象

在Swift中,将AddIndexPublisher定义为类时,使用Self.Failure和Self.Output会触发编译错误,但定义为结构体时无报错。示例代码及编译错误如下:

class AddIndexPublisher<InputP: Publisher>: Publisher {
    typealias Output = (InputP.Output, Int)
    typealias Failure = InputP.Failure

    let ip: InputP

    init(ip: InputP) {
        self.ip = ip
    }

    func receive<S>(subscriber: S)
    // 'Failure' is not a member type of type 'Self'
    // 'Output' is not a member type of type 'Self'
    where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
    {
        let sub = AddIndexSubscription<
                        // 'Failure' is not a member type of type 'Self'
                        S, InputP, Self, InputP.Output, Self.Failure
                    >(sub: subscriber, ipub: ip, opub: self)
        subscriber.receive(subscription: sub)
    }
}

移除Self.后类可正常编译,以下是该类与结构体差异的原因及Swift规范背景说明。

差异原因

  • 结构体(值类型)的确定性:结构体不存在继承和重写机制,Self在编译期就明确指向当前结构体类型,编译器可以直接解析Self.Failure为结构体中定义的类型别名,没有歧义。
  • 类(引用类型)的多态不确定性:类支持继承,子类可以重写父类的关联类型。在父类的方法定义中,Self可能指向子类实例,编译器无法在编译期确定Self.Failure到底是父类的定义还是子类重写后的版本,因此会抛出编译错误。

直接使用Failure和Output时,编译器会绑定到当前类的类型别名定义,规避了子类重写带来的不确定性,所以能正常编译。

Swift规范背景

Swift类型系统为保证类型安全,针对类和结构体的特性制定了不同的关联类型查找规则:

  • 结构体作为值类型,没有多态特性,Self的指向完全确定,允许直接通过Self.访问关联类型。
  • 类作为引用类型,多态特性导致Self的动态绑定可能带来类型不匹配风险,因此编译器在父类语境下禁止通过Self.访问关联类型,避免子类重写后破坏父类方法的类型约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:50:25