Почему для построения объекта типа класса "someClass" с значением метатипа используйте "обязательный" инициализатор?

class Animal {
    class func generate() -> Animal {
        return self()
    }
}

Компилятор жалуется на создание объекта типа класса "Animal" с значением метатипа должен использовать "обязательный" инициализатор

Я могу это понять. Если я напишу подкласс следующим образом:

class SubAnimal: Animal {
    let head: Int
    init(head: Int) {
        self.head = head
        super.init()
    }
}

Он наследует метод класса Animal generate() но не наследует инициализатор по умолчанию init(). Так SmallAnimal.generate() фактически вызывает SmallAnimal(), но SmallAnimal не имеет инициализатора init() ! Конечно, это то, что компилятор хочет предотвратить.

Меня смущает аналогичная проблема.

class someClass {

}
let anotherClass = someClass.self
let anotherObject = anotherClass()

Компилятор все еще жалуется на создание объекта типа класса "Animal" с значением метатипа, который должен использовать "требуемый" инициализатор.

На этот раз я не понимаю. anotherClass - значение anotherClass, но какой плохой результат будет вызван?

Я знаю, как решить эту проблему, добавив required init() {}. Но я действительно хочу знать причину второго дела.

Ответы

Ответ 1

Рассмотрим случай, когда мы также имеем подкласс:

class SomeClass {

}

class SomeSubclass : SomeClass {

}

Если вы сохраните тип класса в переменной:

var anotherClass = SomeClass.self

Переменная anotherClass имеет тип SomeClass.Type.

Вы можете позже назначить эту переменную подклассу:

anotherClass = SomeSubclass.self

Это верно, поскольку SomeSubclass.Type - это SomeClass.Type. На этом этапе anotherClass() завершится с ошибкой, если инициализатор не будет реализован в подклассе. Это то, что защищает компилятор.

В вашем примере кода это невозможно: вы использовали let вместо var поэтому изменение типа невозможно. Может быть, проверки безопасности просто недостаточно нюансированы, чтобы заметить это.