Conformité facultative au protocole Swift via non facultative
J'ai un protocole avec une propriété facultative.
La plupart des types conformes à ce protocole auront une propriété facultative correspondante. Cependant, on a une propriété non facultative du même type et du même nom.
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'
}
En appuyant sur "Fix - Voulez-vous ajouter des talons de protocole ?" de Xcode. ajoute la version facultative de la propriété, mais la structure contient désormais des noms de variables en double non valides :
struct StructB: SomeProtocol {
let foo: Int
var foo: Int? { return foo } // Invalid redeclaration of 'foo'
}
Dans le { get }
seul cas, j'avais supposé que cela "fonctionnerait simplement" car le non-facultatif satisfaisait toujours les contraintes du facultatif, de la même manière que vous pouvez renvoyer un non-facultatif dans une fonction avec un type de retour facultatif. Mais apparemment ce n'est pas le cas.
Cela fonctionne de la même manière pour les fonctions ; un protocole func bar() -> Int?
n'est pas satisfait par un type conforme déclarant func bar() -> Int
.
Existe-t-il un moyen de contourner ce problème ? Je préférerais ne pas renommer les variables ou ajouter des getters intermédiaires.
Cette situation a-t-elle été envisagée pour Swift ? Quelle est la raison de ne pas autoriser un non-facultatif à satisfaire une variable de protocole facultative ?
Réponses
Si le protocole fournit une implémentation par défaut qui renvoie un facultatif :
protocol SomeProtocol {
var foo: Int? { get }
}
extension SomeProtocol {
var foo: Int? { return nil }
}
les types conformes au protocole peuvent alors fournir une version prioritaire non optionnelle de la variable/fonction :
struct StructB: SomeProtocol {
let foo: Int
}
J'ai trouvé ceci discuté sur le forum Swift Evolution:
À première vue, je pensais qu'il existait une règle qui nous permettait de satisfaire aux exigences du protocole avec des types non facultatifs, mais cela a entraîné une erreur. Ce n'est qu'après une enquête plus approfondie que j'ai remarqué qu'une implémentation par défaut doit exister afin de « en quelque sorte remplacer » l'exigence avec une version non facultative.
https://forums.swift.org/t/how-does-this-rule-work-in-regard-of-ambiguity/19448
Cette équipe Swift discute également de l'autorisation de types non facultatifs pour satisfaire les protocoles à valeur facultative :
Cela aurait-il un sens d'autoriser la satisfaction des exigences de protocole avec des types non facultatifs, comme avec des init faillibles ? (Probablement avec une promotion optionnelle implicite.)
Ouais, totalement ! À l'exception de la partie où cela modifie le comportement du code existant, nous devons donc être très prudents à ce sujet. Ceci est considéré comme faisant partie de [SR-522] Les fonctions de protocole ne peuvent pas avoir de retours covariants
qui est suivi sur Stack Overflow ici :
Pourquoi une exigence de propriété get-only dans un protocole ne peut-elle pas être satisfaite par une propriété conforme ?