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

Swift中如何定义TestDBAPI以满足DBAPIProtocol的泛型约束

问题分析

错误根源在于DBAPIProtocol中notesFetcher的返回类型定义逻辑矛盾:你要求返回的ObjectFetcherProtocol必须将Object关联类型指定为any ConvertibleValueObservableObject<Note>(存在类型),但TestNoteFetcher的Object是具体的TestNote类型。Swift不允许将具体类型的关联类型自动适配为存在类型的关联类型,两者不符合协议约束的一致性要求。

解决方案

修改DBAPIProtocol中notesFetcher的类型定义,仅约束ConvertValue为Note即可——因为ObjectFetcherProtocol本身已经规定Object: ConvertibleValueObservableObject<ConvertValue>,只要ConvertValue是Note,Object自然满足ConvertibleValueObservableObject<Note>的要求,无需额外指定Object的存在类型。

修改后的完整代码:

import Combine

// For Value
public enum WrappedID: Equatable, Identifiable, Sendable, Hashable {
    case string(String)
    case integer(Int)

    public var id: Self {
        self
    }
}

public protocol BaseValueProtocol: Equatable, Identifiable, Sendable {
    var id: WrappedID { get }
}

public struct Note: BaseValueProtocol {
    public var id: WrappedID
    public var index: Int

    public init(id: WrappedID, index: Int) {
        self.id = id
        self.index = index
    }
}

// For Object 
public protocol ConvertibleValueObservableObject<Value>: ObservableObject, Equatable, Identifiable where ID == WrappedID {
    associatedtype Value: BaseValueProtocol
    func convertToValueType() -> Value
}

public final class TestNote: ConvertibleValueObservableObject {
    public static func == (lhs: TestNote, rhs: TestNote) -> Bool {
        true
    }

    public var id: WrappedID {
        .integer(1)
    }

    public func convertToValueType() -> Note {
        .init(id: .integer(1), index: 0)
    }
}

// For Fetcher
public protocol ObjectFetcherProtocol<Object,ConvertValue> {
    associatedtype ConvertValue: BaseValueProtocol
    associatedtype Object: ConvertibleValueObservableObject<ConvertValue>
    var stream: AsyncPublisher<AnyPublisher<[Object], Never>> { get }
}

public final class TestNoteFetcher: ObjectFetcherProtocol {
    public typealias ConvertValue = Note
    public typealias Object = TestNote

    public var stream: AsyncPublisher<AnyPublisher<[TestNote], Never>> {
        sender.eraseToAnyPublisher().values
    }

    public var sender: CurrentValueSubject<[TestNote], Never>
    public init(_ notes: [TestNote] = []) {
        sender = .init(notes)
    }
}

// For API - 修改此处的notesFetcher类型
public protocol DBAPIProtocol {
    var notesFetcher: () async -> any ObjectFetcherProtocol where ConvertValue == Note { get set }
}

public final class TestDBAPI: DBAPIProtocol {
    public var notesFetcher: () async -> any ObjectFetcherProtocol where ConvertValue == Note = {
        TestNoteFetcher([])
    }
}
灵活扩展方案

如果需要让DBAPIProtocol支持多种类型的Fetcher(不止Note),可以将协议改为泛型协议,进一步保留泛型灵活性:

public protocol DBAPIProtocol<Value> {
    associatedtype Value: BaseValueProtocol
    var notesFetcher: () async -> any ObjectFetcherProtocol where ConvertValue == Value { get set }
}

// 实现时指定关联类型为Note
public final class TestDBAPI: DBAPIProtocol {
    public typealias Value = Note
    public var notesFetcher: () async -> any ObjectFetcherProtocol where ConvertValue == Note = {
        TestNoteFetcher([])
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:15:34