我试图获得一个实现一组协议的容器,这些协议作为参数传递给原始容器上的函数。
struct Container {
let someProperty: String
let otherProperty: String
}
// Subcontainers
protocol Base {}
protocol SomePropertyContainer: Base {
var someProperty: String { get }
}
protocol OtherPropertyContainer: Base {
var otherProperty: String { get }
}
extension Container: SomePropertyContainer, OtherPropertyContainer {}
// Sub Container Provisioning Protocol
protocol SubContainerProviderProtocol {
func subContainer<T: Base>(protos: T.Type) -> T?
}
extension Container: SubContainerProviderProtocol {
func subContainer <T: Base>(protos: T.Type) -> T? {
return self as? T
}
}
// Example container
let subContainerProvider: SubContainerProviderProtocol = Container(someProperty: "Why does this not work!", otherProperty: "Seriously.")
启动并运行它可以让我将ContainerProviderProtocol
注入消费者,同时让他们可以自己指定他们实际想要的SubContainer
。
例如一个只对someProperty
感兴趣的类可能看起来像这样
// Example Container Provider consumer
class SomeClass {
let subContainerProvider: SubContainerProviderProtocol
init(subContainerProvider: SubContainerProviderProtocol) {
self.subContainerProvider = subContainerProvider
}
func printSomeProperty() {
let someProperty = subContainerProvider
.subContainer(protos: SomePropertyContainer.self)?
.someProperty
print(someProperty)
}
}
// Example call
let someClass = SomeClass(subContainerProvider: subContainerProvider)
someClass.printSomeProperty() // "Why does this not work!"
对于依赖注入和可测试性,此解决方案将是不可思议的。
但是限制T: Base
导致编译器错误
在参数类型'SomePropertyContainer.Protocol'中,'SomePropertyContainer'不符合预期的类型'Base'
未指定与Base的一致性将进行编译,但也允许将任何类型作为T传递。
我在附加协议中尝试了关联类型,但是还没有弄清楚。尽管这个问题非常有趣,但我的想法已用尽。
可能与https://bugs.swift.org/browse/SR-55相关(但不完全相同)
答案 0 :(得分:0)
这是问题所在:在某些时候,您必须开始使用实际类型,而不仅仅是协议。您的行:
func container<T: Base>(protos: T.Type) -> T?
告诉编译器您将给此函数一个类型,通常为T
,它符合协议Base
,而不是另一个协议。您需要这样的东西:
class SPC: SomePropertyContainer {
var someProperty: String = ""
}
class SomeClass {
let containerProvider: ContainerProviderProtocol
init(containerProvider: ContainerProviderProtocol) {
self.containerProvider = containerProvider
}
func printSomeProperty() {
let someProperty = containerProvider
.container(protos: SPC.self)?
.someProperty
print(someProperty)
}
}
SPC是一种符合SomePropertyContainer协议的类型,该协议本身也符合Base协议,因此这就是您的代码所期望的。