Protocolo Swift Conformidade opcional via não opcional

Aug 18 2020

Eu tenho um protocolo com uma propriedade opcional.

A maioria dos tipos em conformidade com este protocolo terá uma propriedade opcional correspondente. No entanto, tem-se uma propriedade não opcional do mesmo tipo e nome.

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'
}

Pressionando "Fix - Do you want to add protocol stubs" do Xcode? O botão adiciona a versão opcional da propriedade, mas a estrutura agora tem nomes de variáveis ​​duplicados inválidos:

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

No { get }único caso, presumi que isso "simplesmente funcionaria" devido ao não-opcional sempre satisfazendo as restrições do opcional, semelhante a como você pode retornar um não-opcional em uma função com um tipo de retorno opcional. Mas aparentemente esse não é o caso.

Isso também funciona da mesma forma para funções; um protocolo func bar() -> Int?não é satisfeito por um tipo conforme declarando func bar() -> Int.

Existe alguma maneira de contornar esse problema? Eu preferiria não renomear as variáveis ​​ou adicionar getters intermediários.

Essa situação foi considerada para Swift? Qual é a justificativa para não permitir que um não-opcional satisfaça uma variável de protocolo opcional?

Respostas

pkamb Aug 19 2020 at 00:34

Se o protocolo fornecer uma implementação padrão que retorne um opcional:

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

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

os tipos em conformidade com o protocolo podem fornecer uma versão não opcional substituta da variável/função:

struct StructB: SomeProtocol {
    let foo: Int
}

Eu encontrei isso discutido no fórum Swift Evolution:

À primeira vista, pensei que havia uma regra que nos permite satisfazer os requisitos de protocolo com tipos não opcionais, mas isso resultou em um erro. Somente após uma investigação mais aprofundada, notei que uma implementação padrão deve existir para 'meio que substituir' o requisito por uma versão não opcional.

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

Esta equipe do Swift também discute permitir que tipos não opcionais satisfaçam protocolos de valor opcional:

Faria algum sentido permitir a satisfação dos requisitos de protocolo com tipos não opcionais, como init's com falhas? (Provavelmente com alguma promoção opcional implícita.)

Sim, totalmente! Exceto pela parte em que isso muda o comportamento do código existente, então teríamos que ter muito cuidado com isso. Isso é considerado parte de [SR-522] Funções de protocolo não podem ter retornos covariantes

que é rastreado no Stack Overflow aqui:

Por que um requisito de propriedade get-only em um protocolo não pode ser satisfeito por uma propriedade que esteja em conformidade?