Протокол с дженериками выдает ошибку при использовании в качестве свойства для вызова метода

у меня есть протоколSomeObjectFactoryчей методcreateSomeObjectWithConfiguration(_ config: SomeObjectConfiguration<T>)используется внутри класса Builder. Когда я попытался скомпилировать этот код с помощью Swift 5.7, я столкнулся с ошибкой.

Член «configWithExperience» не может использоваться для значения типа «любая конфигурацияFactory»; рассмотрите возможность использования общего ограничения вместо этого

Вот реализация ниже

      import Combine
import Foundation

final class SomeObject<T: Combine.Scheduler> {}

struct Experience {
    let id: String
}

struct SomeObjectConfiguration<T: Combine.Scheduler> {
    let scheduler: T
}

protocol SomeObjectFactory {
    associatedtype T: Combine.Scheduler
    func createSomeObjectWithConfiguration(_ config: SomeObjectConfiguration<T>) -> SomeObject<T>
}

protocol ConfigurationFactory {
    associatedtype T: Combine.Scheduler
    func configWithExperience(_ experience: Experience) -> SomeObjectConfiguration<T>
}

final class Builder<T: Combine.Scheduler> {
    
    private let configurationFactory: any ConfigurationFactory
    
    init(configurationFactory: any ConfigurationFactory) {
        self.configurationFactory = configurationFactory
    }
    
    func createSomeObject(_ experience: Experience) {
        let someObjectConfiguration: SomeObjectConfiguration<T> = configurationFactory.configWithExperience(experience)
    }
}

Я надеялся создать someObjectConfiguration из экземпляра ConfigurationFactory Builder.

1 ответ

any ConfigurationFactoryдействительно означает, любой ConfigurationFactory. Нет никакой гарантии, чтоConfigurationFactory.Tэтого завода будет таким же, как иBuilder.Tчто его содержит. Вам нужно добавить ограничение, что эти два должны совпадать.

Один из способов сделать это — использовать первичный связанный тип, например:

      // Make `T` a primary associated type
// https://github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md

+protocol ConfigurationFactory<T> {
-protocol ConfigurationFactory {
    associatedtype T: Combine.Scheduler
    func configWithExperience(_ experience: Experience) -> SomeObjectConfiguration<T>
}

final class Builder<T: Combine.Scheduler> {

+    // Constant the `T` of the factory to be the `T` of this builder   
+    private let configurationFactory: any ConfigurationFactory<T>
-    private let configurationFactory: any ConfigurationFactory
    
     // Likewise, update the initializer to match
+    init(configurationFactory: any ConfigurationFactory<T>) {
-    init(configurationFactory: any ConfigurationFactory) {
        self.configurationFactory = configurationFactory
    }
    
    func createSomeObject(_ experience: Experience) {
        let someObjectConfiguration: SomeObjectConfiguration<T> = configurationFactory.configWithExperience(experience)
    }
}
Другие вопросы по тегам