Home > front end >  How to create an instance that satisfies the generic requirements
How to create an instance that satisfies the generic requirements

Time:11-04

I have created the following code and everything works fine except the definition of TestDBAPI.

When I want to create a type that conforms to the DBAPIProtocol protocol, it is always impossible to generate a type instance that satisfies the generic constraints

Please, how can I define TestNoteFetcher to satisfy the protocol requirement of DBAPIProtocol.

ps: I hope the flexibility of generic definitions can be maintained in DBAPIProtocol

thanks

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
public protocol DBAPIProtocol {
    var notesFetcher: () async -> any ObjectFetcherProtocol<any ConvertibleValueObservableObject<Note>, Note> { get set }
}

// get error in here . Cannot convert value of type 'TestNoteFetcher.Object' (aka 'TestNote') to closure result type 'any ConvertibleValueObservableObject<Note>'

public final class TestDBAPI: DBAPIProtocol {
    public var notesFetcher: () async -> any ObjectFetcherProtocol<any ConvertibleValueObservableObject<Note>, Note> = {
        TestNoteFetcher([])
    }
}

enter image description here

CodePudding user response:

Since your closure returns too many anys, the compiler got confused & is telling you that TestNoteFetcher does not conform any ObjectFetcherProtocol. Generics are your friend, you can use associatedtype to skip all this code & fix the issue:

public protocol DBAPIProtocol {
    associatedtype Fetcher: ObjectFetcherProtocol
    var notesFetcher: () async -> Fetcher { get set }
}
public final class TestDBAPI: DBAPIProtocol {
    public var notesFetcher: () async -> TestNoteFetcher = {
        TestNoteFetcher([])
    }
}
  • Related