在我的实际代码中,MyFoo对象执行其他一些我不想分享的实现细节。因此,我试图将其隐藏在我的Foo协议之后,但是,我找不到必要的where子句来正确映射该类型:
protocol Foo {
associatedtype Bar
func process(bar:Bar)
}
class MyFoo<T>: Foo {
func process(bar: T) {}
}
class Buzz<U> {
private let myFoo = MyFoo<U>()
init<BarProcessor:Foo>(block:(BarProcessor)->Void) where BarProcessor.Bar == U {
block(myFoo) // error: '(@lvalue MyFoo<U>) -> Void' is not convertible to '(BarProcessor) -> Void'
}
}
还是有一个更基本的概念,我在这里错过了为什么这不起作用?
答案 0 :(得分:1)
这并不意味着您的意思:
init<BarProcessor:Foo>(block:(BarProcessor)->Void) where BarProcessor.Bar == U
这是试图将BarProcessor
视为专门的协议。但事实并非如此。 BarProcessor
这是一个具体的类型。所以你传递的块接受一些特定的(但是通用的)类型。然后,您尝试将MyFoo
传递给它,这可能不是特定类型。
当您发现自己以这种方式混合协议和泛型时,您可能过度使用了协议。摆脱Foo
。协议不是隐藏实现细节的方法。隐藏实施细节的工具是访问控制(private
和internal
)。
如果你想完全隐藏类型,那就是类型橡皮擦,而不是协议。例如(在没有“Foo”和“Bar”的情况下将事物重命名为他们的意思):
private struct MyProcessor<T> {
func process(element: T) {}
}
// Type-erases MyProcessor
struct Processor<T> {
fileprivate let processor: MyProcessor<T>
func process(element: T) { processor.process(element: element) }
}
class Machine<U> {
private let myProcessor = MyProcessor<U>()
init(block: (Processor<U>)->Void) {
block(Processor(processor: myProcessor))
}
}
或者,如果你想要私有的处理器的多个内部实现,你可以使用私有协议,但关键是外部世界只看到类型橡皮擦,而不是PAT。
private protocol Processing {
associatedtype Element
func process(element: Element)
}
private struct MyProcessor<T>: Processing {
func process(element: T) {}
}
struct Processor<T> {
private let _process: (T) -> ()
fileprivate init<P: Processing>(_ processor: P) where P.Element == T {
_process = processor.process
}
func process(element: T) { _process(element) }
}
class Machine<U> {
private let myProcessor = MyProcessor<U>()
init(block: (Processor<U>)->Void) {
block(Processor(myProcessor))
}
}