Протокол с дженериками выдает ошибку при использовании в качестве свойства для вызова метода
у меня есть протокол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)
}
}