Проблема, с которой я столкнулся, заключалась в том, что T
не может быть выведено в случае MyThing
.Компилятор не очень полезен, когда дело доходит до сообщений об ошибках (однажды мне сказали Cannot convert return expression of type 'T' (aka 'MyImplementation') to return type 'T'
)
Решение состоит в том, чтобы дать компилятору какой-то способ узнать, каким должен быть T
(еслиВы хотели, чтобы это было без ограничений, используйте AnyObject
, а не T
).
В моем случае я хотел вернуть значение типа Self (тип реализации).Это усложняет вещи больше, чем ваши обычные проблемы с POP, поскольку вы не можете ссылаться на Self в классе / статической функции.
Чтобы обойти это, я использую Swift associatedtype
, который позволяет нам устанавливать именованный заполнительдля использования по протоколу.Поскольку мы определяем это на уровне протокола и предоставляем значение, мы можем установить именованную ссылку на собственный тип разработчиков.
associatedtype MyType = Self.Type
Примечание , что associatedtype MyType = Self
не будетработать, поскольку self в этом контексте является протоколом , а не типом окончательной реализации (о котором мы пока не знаем, и мы / компилятор не узнаем, пока какой-то объект не реализует протокол).
Поскольку мы предоставляем значение, когда мы реализуем наш протокол, тип уже ограничен!Поскольку ограничение относится только к типу реализации, реализации протокола достаточно для определения типа (круто).Самое приятное то, что теперь я могу исключить ссылку на Self в моем class func
определении:
protocol MakesSelf {
associatedtype MyType = Self.Type
static func getInstance() -> MyType
}
class MyImplementation: MakesSelf {
class func getInstance() -> MyImplementation {
print("Hello")
return MyImplementation()
}
}
let myThing = MyImplementation.getInstance()
Чтобы быть супер ясным здесь - класс MyImplementation имеет typealias, называемый MyType, как указано в протоколе.Когда я компилирую, псевдоним будет ссылаться на текущую реализацию.Теперь, когда я реализую функцию getInstance, MyImplementation соответствует MyType.
Обратите внимание , что я должен написать свою подпись функции в виде class func getInstance() -> MyImplementation
, а не class func getInstance() -> MyType
.Это потому, что я возвращаю результат вызова функции MyImplementation()
, который, как оказалось, соответствует ограничению MyType.Это не то же самое, что сказать, что MyImplementation может быть неявно преобразовано в MyType.
Для хорошего прочтения о попытке сделать спецификацию функции протокола для возврата self смотрите здесь , но я хотел опубликоватьконкретное решение и объяснение.