Почему обязательное ключевое слово init обязательно внутри общего предложения Array where? - PullRequest
0 голосов
/ 12 ноября 2018

В этом индексе:

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

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Ключевое слово required означает, что наследующие классы должны обеспечивать реализацию метода.

И extension Array where Element: Foo означает, что расширение должно работать для всех классов, унаследованных от Foo, поэтому все они required должны реализовать init(key: String, value: Any?).

Поэтому для этого необходимо добавить ключевое слово required.

Если бы это было extension Array where Element == Foo, вам не нужно было бы иметь required, потому что для типа Foo определено init с правильной подписью, и нет необходимости в каких-либо проверках.

Выполнение Foo final (final class Foo {}) устранит необходимость в required.

0 голосов
/ 12 ноября 2018

Вам нужно пометить инициализатор required, потому что вы используете его из общего расширения, которое применяется ко всем типам, унаследованным от Foo (включая сам Foo). Однако, если вы не пометили инициализатор как required, ваши подклассы Foo могут не наследовать этот инициализатор, если они определили хотя бы один назначенный инициализатор, как описано в Автоматическое наследование инициализатора .

Таким образом, если вы не отметили init(key: String, value: Any?) инициализатор Foo required, ваше универсальное расширение Array не может гарантировать, что метод инициализатора, вызываемый в расширении, существует для всех типов, к которым применяется расширение.

Если вы хотите применить расширение только к классу Foo и не хотите применять его к его подклассам, вы можете использовать extension Array where Element == Foo {..., и в этом случае вам не нужно будет отмечать инициализатор как необходимый , поскольку тип Foo гарантированно имеет этот инициализатор.

...