Swift Protocol Необязательное соответствие через Необязательное

Aug 18 2020

У меня есть протокол с необязательным свойством.

Большинство типов, соответствующих этому протоколу, будут иметь соответствующее необязательное свойство. Однако у одного есть необязательное свойство того же типа и имени.

protocol SomeProtocol {
    var foo: Int? { get }
}

struct StructA: SomeProtocol {
    let foo: Int?
}

struct StructB: SomeProtocol {
    let foo: Int // Type 'StructB' does not conform to protocol 'SomeProtocol'
}

Нажатие Xcode "Исправить - Вы хотите добавить заглушки протокола?" Кнопка добавляет необязательную версию свойства, но теперь в структуре есть недопустимые повторяющиеся имена переменных:

struct StructB: SomeProtocol {
    let foo: Int
    var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}

В { get }случае -only я предполагал, что это будет «просто работать» из-за того, что необязательное всегда удовлетворяет ограничениям необязательного, аналогично тому, как вы можете вернуть необязательное в функции с необязательным типом возвращаемого значения. Но, видимо, это не так.

То же самое работает и с функциями; протокол func bar() -> Int?не удовлетворяется объявлением соответствующего типа func bar() -> Int.

Есть ли способ обойти эту проблему? Я бы предпочел не переименовывать переменные и не добавлять промежуточные геттеры.

Рассматривалась ли такая ситуация для Swift? Что является рациональным в том, чтобы не позволять необязательному удовлетворять необязательной переменной протокола?

Ответы

pkamb Aug 19 2020 at 00:34

Если протокол предоставляет реализацию по умолчанию, которая возвращает необязательный параметр:

protocol SomeProtocol {
    var foo: Int? { get }
}

extension SomeProtocol {
    var foo: Int? { return nil }
}

Типы, соответствующие протоколу, могут затем предоставить замещающую необязательную версию переменной / функции:

struct StructB: SomeProtocol {
    let foo: Int
}

Я нашел это обсужденным на форуме Swift Evolution:

На первый взгляд я подумал, что есть правило, позволяющее удовлетворить требования протокола с необязательными типами, но это привело к ошибке. Только после дальнейшего исследования я заметил, что должна существовать реализация по умолчанию, чтобы «отчасти переопределить» требование необязательной версией.

https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448

Эта команда Swift также обсуждает возможность соответствия необязательных типов протоколам с необязательными значениями:

Имеет ли смысл разрешать удовлетворение требований протокола с помощью необязательных типов, например, с ошибочными инициализациями? (Вероятно, с некоторым неявным необязательным продвижением.)

Да, конечно! За исключением той части, где это изменяет поведение существующего кода, поэтому нам следует быть очень осторожными с этим. Это считается частью [SR-522]. Функции протокола не могут иметь ковариантный возврат.

который отслеживается в Stack Overflow здесь:

Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?