Почему не может быть требованием свойства 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. Почему это не должно работать? Это недостаток Свифта, или есть причина, почему это имеет смысл?

Нет никакой реальной причины, почему это не должно быть возможным, требование свойства только для чтения может быть ковариантным, поскольку возврат экземпляра 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.

  • Swift 3.0: ошибка компилятора при вызове глобальной func min (T, T) в массиве или расширении словаря
  • Добавление элементов в массив Swift для нескольких streamов, вызывающих проблемы (поскольку массивы не являются streamобезопасными) - как мне обойти это?
  • Пример быстрого продления
  • Можете ли вы переопределить между расширениями в Swift или нет? (Компилятор кажется смущенным!)
  • Как применить тип к экземпляру NSFetchRequest?
  • Передача массива функции с переменным числом аргументов в Swift
  • Вызывается метод расширения Swift, а не метод, реализованный в подclassе
  • Передача списков из одной функции в другую в Swift
  • Static vs функции / переменные classа в classах Swift?
  • Как перечислить перечисление со строковым типом?
  • Вычислить возраст с даты рождения с использованием NSDateComponents в Swift
  • Давайте будем гением компьютера.