2017-11-11 156 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