代码之家  ›  专栏  ›  技术社区  ›  Benjohn

符合返回PAT的通用协议方法

  •  2
  • Benjohn  · 技术社区  · 6 年前

    我想声明与以下类似的通用协议:

    protocol Factory {
        func createWidget<T, TWidget>(_ t: T) -> TWidget 
        where TWidget: Widget, TWidget.T == T
    }
    
    protocol Widget {
        associatedtype T
        func get() -> T
    }
    

    我希望我能实现 Factory 返回自己的混凝土和不透明 Widget 使用隐藏的实现。

    下面是一个未能构建的示例实现:

    struct ConcreteFactory: Factory {
        func createWidget<T, TWidget>(_ t: T) -> TWidget 
        where TWidget: Widget, TWidget.T == T {
            // This line has an error…
            return ConcreteWidget(widgetValue: t)
        }
    }
    
    struct ConcreteWidget<T>: Widget {
        let widgetValue: T
    
        init(widgetValue: T) {
            self.widgetValue = widgetValue
        }
    
        func get() -> T {
            return widgetValue
        }
    }
    

    但是,这并不编译。

    我也试过吃 ConcreteFactory 归还 ConcreteWidget ,但错误是 不符合 .

    1 回复  |  直到 6 年前
        1
  •  4
  •   Sven    6 年前

    这行不通。当你 你的 createWidget 方法指定两种类型 T TWidget

    struct MyWidget: Widget { 
       func get() -> Int { ... }
    }
    
    let widget: MyWidget = factory.createWidget(12)
    

    在这个例子中 MyWidget T Int . 这很好地说明了为什么你的方法行不通。您不能分配一个 ConcreteWidget<Int> 类型的变量 MyWidget

    你需要的是一个 用于您的小部件。目前您必须自己编写,但将来编译器有望在需要时自动生成它们。

    struct AnyWidget<T>: Widget {
        private let _get: () -> T
    
        init<Other: Widget>(_ other: Other) where Other.T == T {
            _get = other.get
        }
    
        func get() -> T {
            return _get()
        }
    }
    

    这允许您编写工厂协议和实现:

    protocol Factory {
        func createWidget<T>(_ t: T) -> AnyWidget<T>
    }
    
    struct ConcreteFactory: Factory {
        func createWidget<T>(_ t: T) -> AnyWidget<T> {
                return AnyWidget(ConcreteWidget(widgetValue: t))
        }
    }