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
相关产品推荐
相关产品推荐

