swift - 将支持的方法限制为 Swift 4 中的泛型参数类型

标签 swift generics swift4

给定某个泛型类型的结构,我想将可以调用的方法限制为仅那些属于泛型类型的子类型的方法。

struct ViewBuilder<T:UIView> {

    let parent:UIView

    func createView() -> UIView {
        let view = UIView()
        parent.addSubview(view)
        return view
    }
}

extension ViewBuilder where T:UIButton {

    func createButton() -> UIButton {
        let button = UIButton()
        parent.addSubview(button)
        return button
    }
}

在这段代码中,我指定构建器应该只创建UIControls:

let builder = ViewBuilder<UIControl>(parent:UIView())
let view = builder.createView() // ok
let button = builder.createButton() // 🛑 'UIControl' is not a subtype of 'UIButton'

但是,如您所见,我得到了相反的行为; UIView 不是 UIControlUIButton UIControl。有什么办法可以在 Swift 中做到这一点? (我使用的是 Swift 4。)我已经尝试过一些使用泛型和协议(protocol)的东西,但没有成功。

(我明白为什么上面的代码按它的方式工作,但我正在寻找替代方案来解决整个问题(如果存在的话)。如果有人能提出一个好的解决方案,也许我可以改进这个问题适合。)

最佳答案

无法从子类型中删除方法(T where T:...T 的子类型)。这是类型的一个基本特征。子类型必须能够做类型能做的一切。否则,如果函数采用通用 ViewBuilder<T> , 它怎么知道 createView是否被允许?扩展是扩展。此类消费者甚至可能看不到它们。

原则上,这是您真正要求的:

struct ViewBuilder<T: UIView> {

    let parent: UIView

    func create<U:T>() -> U {
        let view = U()
        parent.addSubview(view)
        return view
    }
}

这提供了一个 create T 的任何子类型的方法, 它本身必须是 UIView 的子类型.不幸的是,这目前不是合法的 Swift ( SR-5213 )。问题在于,受类约束的泛型类型参数本身并不被视为用于约束其他类型参数的类。

考虑到这个限制,在大多数情况下我可能会使用这样的组合:

struct ViewBuilder {
    let parent: UIView

    func create<View: UIView>(_ type: View.Type) -> View {
        let view = View()
        parent.addSubview(view)
        return view
    }
}

struct ControlBuilder {
    private let builder: ViewBuilder
    var parent: UIView { return builder.parent }

    init(parent: UIView) {
        builder = BaseViewBuilder(parent: parent)
    }

    func create<Control: UIControl>(_ type: Control.Type) -> Control {
        return builder.create(type)
    }
}

let builder = ControlBuilder(parent:UIView())
let button = builder.create(UIButton.self)

这里是ControlBuilder哈萨ViewBuilder而不是 ISA ViewBuilder .如果您想接受“可以创建一种 View 的东西”,这会有一些限制,因为由于 SR-5213,几乎不可能(据我所知)创建一个涵盖这两者的协议(protocol)。但是根据您的示例,这看起来符合您的用例。

(不过,我对整个用例有点怀疑。我不清楚“只能包含控件的 View ”有何用处。感觉您真正想要的是 UIView 上的扩展。” Builder”感觉像是试图将 Java 模式导入 Swift 中,但可能不适合。)

关于swift - 将支持的方法限制为 Swift 4 中的泛型参数类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44764776/

相关文章:

ios - 获取当前屏幕亮度

arrays - 如何使用另一个类的变量打印一个类的元素?

c# - 通用方法问题/错误?

swift - 类型 'String' 的 UILabel 值没有成员 'text'(静态自定义单元格)

ios - 如何在我的 Swift 类中使用 Objective-c 方法

swift 4 firebase GeoPoint 解码

ios - 取消在 DispatchQueue 中等待执行的 DispatchWorkItem

swift - 验证纹理尺寸:759: failed assertion `MTLTextureDescriptor has width (45000) greater than the maximum allowed size of 16384.'

java - 通用 OR 而不是 AND <T extends Number |字符序列>

java - 模拟返回带有捕获泛型的迭代器的方法