带有泛型的协议在用作调用方法的属性时抛出错误

问题描述 投票:0回答:1

我有一个协议

SomeObjectFactory
,它的方法
createSomeObjectWithConfiguration(_ config: SomeObjectConfiguration<T>)
在类Builder中使用。当我尝试用 Swift 5.7 编译这段代码时,我遇到了一个错误

成员“configWithExperience”不能用于“any”类型的值 配置工厂';考虑改用通用约束

下面是实现

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)
    }
}

我希望从 Builder 的 configurationFactory 实例创建一个 someObjectConfiguration。

swift generics protocols swift-protocols swift5.7
1个回答
2
投票

any ConfigurationFactory
确实意味着,any
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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.