Это очень похоже на Протокол веселья c Возвращение Self , но достаточно отличается, что, вероятно, стоит ответить отдельно. Здесь есть две проблемы.
Первая проблема - зачем вам нужна final
. Как и в предыдущем вопросе, проблема заключается в том, что вы даете обещание, которое компилятор не может доказать, что вы будете его выполнять.
Рассмотрите следующий подкласс:
class LocalFireman: Fireman {
let zipcode: String
init(zipcode: String) { self.zipcode = zipcode }
}
Что следует сделать LocalFireman.shared
вернуть? Он не может вернуть пожарного. Вы сказали, что он должен вернуть Self (т.е. LocalFireman). И он не может вернуть LocalFireman
, так как у него нет почтового индекса для инициализации. Так что же теперь?
Swift не позволяет вам войти в этот угол, требуя от вас либо прибить определенный c тип shared
(то есть это всегда будет Fireman
, даже если вы вызовите его для подкласса), или вам нужно пообещать, что подклассов не будет, или вам нужно, чтобы все подклассы реализовали init
:
required init() {}
ОК, но вы дошли до этого. Вы отметили это final
, и он все еще жалуется. Теперь вы попали в ограничение компилятора. Весь смысл Self
- ковариация; это тип Dynami c в точке вызова, а не тип STATI c в контексте . Это не просто удобный способ сказать «мой тип», и это был выбор (хотя я думаю, что это может измениться). Это означает «мой ковариантный тип», даже если вы находитесь в ситуации, когда не может быть никаких подтипов.
Все, что сказано, учитывая private
init, я запутался, почему вы говорите, отмечая его final
"против моей воли". Если все init
являются частными, это не может быть разделено на подклассы в любом случае, поэтому кажется, что вам нужен конечный класс, и если это так, то просто поместите имя класса, куда он идет. Self
не для этой проблемы (сегодня).
Это оставляет открытым вопрос о том, почему вы не можете сделать это с требуемым init. Self
как «тип класса» и Self
как «тип объекта, соответствующего протоколу» рассматриваются как одно и то же. Таким образом, вы не можете думать об этом только в классовой ситуации; все может «наследовать» (соответствовать) протоколу. Так что Self
потенциально может ссылаться на структуру. Структуры могут быть любого размера. Таким образом, разрешение хранимого свойства типа Self
создает проблемы с разметкой памяти. (Я не думаю, что Swift обещает, что классы всегда будут реализованы как указатель, так что это может вызвать ту же проблему для классов, по крайней мере, в принципе.)
Вы можете вернуть значение типа Self
из функции, но вы не можете поместить ее в сохраненное свойство (это верно как для свойств stati c и non-stati c), так и Swift также не допускает их для вычисляемых свойств (I Предположим, это только для согласованности). Таким образом, допустимо (и действительно полезно) следующее:
class Fireman {
required init() {}
static func make() -> Self { return Self() }
}
И это то, для чего Self
.