2017-11-11 89 views
0

在我的实际代码中,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' 
    } 
} 

还是有我丢失在这里作为一个更基本的概念为什么这不起作用?

回答

1

这并不意味着你认为它的意思是:

init<BarProcessor:Foo>(block:(BarProcessor)->Void) where BarProcessor.Bar == U 

这是试图把BarProcessor作为已专门的协议。但事实并非如此。 BarProcessor这里是一个具体类型。所以你通过一个接受特定(但通用)类型的块。然后,您尝试将MyFoo传递给它,这可能不是特定类型。

当你发现自己以这种方式混合协议和泛型时,你可能会滥用协议。摆脱Foo。协议不是隐藏实现细节的一种方式。隐藏实现细节的工具是访问控制(privateinternal)。

如果你想完全隐藏类型,这是一个橡皮擦,而不是一个协议。例如(重命名的东西,他们的意思没有“富”与“酒吧”):

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

感谢罗布,这是有道理的。我对代码的做法仍然有点模糊,但我明白了;但是使用type-erasure可以达到我想要的目标。 – SeanCAtkinson