Le mécanisme des subscripts en Swift est apparu avec le langage en 2014 et est destiné à accéder aux données des collections avec une syntaxe plus pratique. Les subscripts permettent d'accéder aux éléments des tableaux, des dictionnaires et d'autres collections via des crochets. Swift moderne permet de créer des subscripts personnalisés pour vos propres types, rendant l'API intuitive comme pour les structures de données standard.
Problème : Auparavant, les méthodes d'accès semblaient plus encombrantes (par exemple, via .getElement(at:)), alors que le subscript rend l'interaction avec le type concise. Cependant, une mauvaise implémentation peut entraîner un code non optimal ou des erreurs d'accès en dehors de la collection.
Solution : Pour implémenter un subscript, on utilise le mot-clé subscript, suivi des paramètres et de la valeur de retour. Un subscript peut être uniquement en lecture, ou en lecture et écriture. De plus, les subscripts peuvent être surchargés pour différents paramètres.
Exemple de code :
struct Matrix { let rows: Int let columns: Int var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
Caractéristiques clés :
Peut-on assigner un subscript uniquement en lecture ? Ou un subscript doit-il toujours avoir get et set ?
Un subscript peut être uniquement en lecture (uniquement get), si l'implémentation ne contient pas de set. Il n'est pas nécessaire d'implémenter les deux accesseurs, ce qui est similaire aux propriétés.
Exemple de code :
subscript(index: Int) -> Int { get { return index * 2 } }
Peut-on passer des paramètres modifiables via inout dans un subscript ?
Non, le subscript ne prend pas en charge les paramètres inout dans la signature. Tous les paramètres des subscripts sont traités comme des constantes let à l'intérieur du corps des accesseurs.
Les subscripts peuvent-ils retourner un type optionnel ?
Oui, les subscripts peuvent retourner des valeurs optionnelles, ce qui est pratique, par exemple, pour un accès sécurisé aux éléments d'une collection sans risque de dépasser les limites du tableau.
Exemple de code :
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
Implémentation d'un subscript sans validation des limites pour un type composite matrix, ce qui provoque un crash de l'application en cas d'erreurs avec l'index.
Avantages :
Inconvénients :
Version optionnelle du subscript ajoutée pour un indexation sécurisée et un traitement des erreurs, rendant l'API explicite et protégée.
Avantages :
Inconvénients :