Почему не может быть требованием свойства get-only в протоколе удовлетворяется свойство, которое соответствует?
Почему в следующем коде возникает ошибка?
protocol ProtocolA { var someProperty: ProtocolB { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // Type 'SomeClass' does not conform to protocol 'ProtocolA' var someProperty: ConformsToB init(someProperty: ConformsToB) { self.someProperty = someProperty } }
Ответ в этом подобном вопросе имеет смысл. Однако в моем примере свойство get-only. Почему это не должно работать? Это недостаток Свифта, или есть причина, почему это имеет смысл?
- Использование в качестве конкретного типа, соответствующего протоколу AnyObject, не поддерживается
- Смутно о объявлениях Swift Array
- Почему я не могу передать Protocol.Type на общий параметр T.Type?
- Метод Non-'@ objc' не удовлетворяет необязательным требованиям протокола @objc
- Запрос HTTP в Swift с методом POST
- swift for loop: для индекса, элемента в массиве?
- «Файл не найден» в заголовке Bridging при импорте объектов Objective-C в проект Swift от CocoaPod
- Быстрое общее недоразумение принуждения
- Использование переменной типа в общем
- как сохранить и прочитать массив массива в NSUserdefaults в swift?
- Как создать глобальную переменную?
- Как получить доступ к аргументам программы в Swift?
- Выберите случайный элемент из массива
Нет никакой реальной причины, почему это не должно быть возможным, требование свойства только для чтения может быть ковариантным, поскольку возврат экземпляра ConformsToB
из свойства, указанного в ProtocolB
является совершенно законным.
В настоящее время Swift не поддерживает его. Для этого компилятор должен будет генерировать бит между таблицей свидетельства протокола и соответствующей реализацией для выполнения необходимых преобразований типов. Например, экземпляр ConformsToB
должен быть помещен в контейнер экзистенции для того, чтобы его набирали как ProtocolB
(и этот способ не может быть вызван, поскольку он может ничего не знать о вызываемой реализации).
Но опять же, нет причин, по которым компилятор не должен этого делать. Откроется несколько отчетов об ошибках, которые являются специфическими для требований к свойствам только для чтения, и этот общий , в котором Слава Пестов, член команды Swift, говорит:
[…] мы хотим, чтобы протокольные свидетели и методы переопределялись в каждом случае, когда разрешено преобразование функций
Так что это определенно похоже на то, что команда Swift хочет реализовать в будущей версии языка.
Тем не менее, в то же время, как говорит @BallpointBen , одним из способов является использование associatedtype
:
protocol ProtocolA { // allow the conforming type to satisfy this with a concrete type // that conforms to ProtocolB. associatedtype SomeProperty : ProtocolB var someProperty: SomeProperty { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // implicitly satisfy the associatedtype with ConformsToB. var someProperty: ConformsToB init(someProperty: ConformsToB) { self.someProperty = someProperty } }
Но это довольно неудовлетворительно, так как это означает, что ProtocolA
больше не используется в качестве типа (поскольку он имеет associatedtype
с associatedtype
требования). Это также изменяет то, что говорит протокол. Первоначально он сказал, что someProperty
может вернуть все, что соответствует ProtocolB
someProperty
– теперь он говорит, что реализация someProperty
имеет дело только с одним конкретным конкретным типом, который соответствует ProtocolB
someProperty
Другим обходным решением является просто определение фиктивного свойства для удовлетворения требования протокола:
protocol ProtocolA { var someProperty: ProtocolB { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // dummy property to satisfy protocol conformance. var someProperty: ProtocolB { return actualSomeProperty } // the *actual* implementation of someProperty. var actualSomeProperty: ConformsToB init(someProperty: ConformsToB) { self.actualSomeProperty = someProperty } }
Здесь мы по существу пишем thunk для компилятора – но это также не особенно приятно, поскольку он добавляет ненужное свойство API.