【问题标题】:Why is required keyword init mandatory inside a generic Array where clause?为什么在通用 Array where 子句中必须使用 required 关键字 init?
【发布时间】:2023-03-29 09:03:01
【问题描述】:

在这个下标代码中:

extension Array where Element: Foo {
    subscript(key: String) -> Any? {
        get {
            return self.first(where: { $0.key == key })
        }
        set {
            self.append(Element(key: key, value: newValue))
        }
    }
}

class Foo {
    var key: String
    var value: Any?

    // Why "required"?
    required init(key: String, value: Any?) {
        self.key = key
        self.value = value
    }
}

为什么required必须在Foo.init前面?

如果我删除它,我会收到此错误:

Constructing an object of class type 'Array<Element>.Element' (aka 'Element') with a metatype value must use a 'required' initializer

【问题讨论】:

    标签: arrays swift generics extension-methods


    【解决方案1】:

    required 关键字意味着继承类必须提供方法的实现。

    extension Array where Element: Foo 意味着扩展应该适用于从Foo 继承的所有类,因此所有required 都可以实现init(key: String, value: Any?)

    因此必须添加required 关键字以确保这一点。

    如果是extension Array where Element == Foo,则不需要required,因为Foo 类型已定义init 并带有正确的签名,无需进行任何检查。

    Foo 设为最终 (final class Foo {}) 也将消除对 required 的需求。

    【讨论】:

      【解决方案2】:

      您需要标记初始化程序required,因为您从通用扩展中使用它,该扩展适用于从Foo 继承的所有类型(包括Foo 本身)。但是,如果您没有将初始化程序标记为 required,那么您的 Foo 子类可能不会继承该初始化程序,以防它们至少定义了一个指定初始化程序,如 Automatic Initializer Inheritance 中所述。

      因此,除非您将 Fooinit(key: String, value: Any?) 初始化器标记为 required,否则您的通用 Array 扩展无法保证扩展中调用的初始化器方法适用于该扩展的所有类型。

      如果您只想将扩展应用到 Foo 类并且不想将其应用到其子类,您可以使用 extension Array where Element == Foo {...,在这种情况下您不需要根据需要标记初始化程序,因为Foo 类型保证具有该初始化程序。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-08
        • 2014-03-12
        • 2013-11-24
        • 1970-01-01
        • 1970-01-01
        • 2018-04-08
        • 1970-01-01
        • 2013-11-23
        相关资源
        最近更新 更多