Swift通用约束无法转换值
问题描述:
在我的实际代码中,MyFoo对象执行其他操作,它们是我不想共享的实现细节。因此,我想后面躲起来,我美孚协议,但是,我无法找到所需的where子句正确映射类型:Swift通用约束无法转换值
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'
}
}
还是有我丢失在这里作为一个更基本的概念为什么这不起作用?
答
这并不意味着你认为它的意思是:
init<BarProcessor:Foo>(block:(BarProcessor)->Void) where BarProcessor.Bar == U
这是试图把BarProcessor
作为已专门的协议。但事实并非如此。 BarProcessor
这里是一个具体类型。所以你通过一个接受特定(但通用)类型的块。然后,您尝试将MyFoo
传递给它,这可能不是特定类型。
当你发现自己以这种方式混合协议和泛型时,你可能会滥用协议。摆脱Foo
。协议不是隐藏实现细节的一种方式。隐藏实现细节的工具是访问控制(private
和internal
)。
如果你想完全隐藏类型,这是一个橡皮擦,而不是一个协议。例如(重命名的东西,他们的意思没有“富”与“酒吧”):
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))
}
}
感谢罗布,这是有道理的。我对代码的做法仍然有点模糊,但我明白了;但是使用type-erasure可以达到我想要的目标。 – SeanCAtkinson