Секрет Self в Swift

Обновление 2019 года: в версии 5.1 Self можно будет использовать в конкретном контексте, а не только в протоколе и его расширениях. Как только версия 5.1 официально зарелизится, я обновлю эту заметку. А пока она отражает реалии Свифта до версии 5.1.

Изучающие язык программирования Swift наверняка знают, что означает ключевое слово self — это указатель на текущий объект внутри экземпляра класса. Совершенно нормальный функционал практически любого объектного языка. Сложности у обывателя могут начаться в момент, когда он сталкивается со статическими методами и свойствами, а также со знаменитой протокольно-ориентированной парадигмой этого языка. Не будем акцентироваться на особенностях протокольной философии, а приступим к самому интересному, с чем наверняка сталкивался всякий.

Я говорю о вызове статического метода из расширения протокола или определении метода протокола, который должен вернуть конечный тип (eventual type). Всё это является частным случаем позднего статического связывания, о котором всякий может нагуглить достаточно материала.

В случае с банальными статическими методами внутри класса или структуры всё просто — метод легко вызвать по названию типа или вызвать функцию type(of: self), которая вернет текущий тип, у которого уже можно вызывать статические методы. Однако если конкретного типа еще нет, а есть только протокол и/или его расширения (то бишь метатип), то язык не даст нам этого сделать, ведь протокол не может содержать реализации, а расширение протокола не считается конкретным кодом, и мы получаем ошибку Static member 'staticMethodName' cannot be used on protocol metatype 'ProtocolName.Protocol'.

Решением является использование ключевого слова Self (именно с большой буквы), которое является указателем на конечный тип, который реализует протокол. В официальной документации языка есть только одно упоминание этого ключевого слова:

In that [protocol] context, Self refers to the eventual type that conforms to the protocol.

Соответственно, работает это ключевое слово только в метатипах (протоколах и их расширениях), а в конкретных классах или структурах вы получите ошибку Use of unresolved identifier 'Self'.

Теги: программирование, swift, self