El mecanismo de subscript en Swift apareció junto con el lenguaje en 2014 y está diseñado para acceder a los datos de colecciones con una sintaxis más conveniente. Los subscripts permiten acceder a los elementos de arreglos, diccionarios y otras colecciones a través de corchetes. Swift moderno permite crear subscripts personalizados para tipos propios, haciendo que la API sea intuitiva, similar a las estructuras de datos estándar.
Problema: Antes, los métodos de acceso eran más engorrosos (por ejemplo, a través de .getElement(at:)), mientras que el subscript hace que la interacción con el tipo sea más concisa. Sin embargo, una implementación incorrecta puede llevar a un código no óptimo o errores de acceso fuera de la colección.
Solución: Para implementar el subscript se utiliza la palabra clave subscript, seguida de los parámetros y el valor de retorno. El subscript puede ser solo de lectura, o para lectura y escritura. Además, los subscripts pueden estar sobrecargados para diferentes parámetros.
Ejemplo de código:
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, "Índice fuera de rango") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Índice fuera de rango") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
Características clave:
¿Se puede asignar un subscript solo para lectura? ¿O debe tener siempre get y set?
El subscript puede ser solo para lectura (solo get) si no hay set en la implementación. No es necesario implementar ambos accesores, lo que es análogo a las propiedades.
Ejemplo de código:
subscript(index: Int) -> Int { get { return index * 2 } }
¿Se pueden pasar parámetros modificables a través de inout en un subscript?
No, el subscript no soporta parámetros inout en la firma. Todos los parámetros de los subscripts son tomados como constantes let dentro del cuerpo de los accesores.
¿Pueden los subscripts devolver un tipo opcional?
Sí, los subscripts pueden devolver valores opcionales, lo que es útil, por ejemplo, para un acceso seguro a los elementos de la colección sin el riesgo de salir del rango del arreglo.
Ejemplo de código:
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
Implementación de un subscript sin validación de límites para un tipo compuesto de matriz, lo que lleva a un fallo de la aplicación ante errores de índice.
Ventajas:
Desventajas:
Se añadió una versión opcional de subscript para indexación segura y manejo de errores, haciendo que la API sea explícita y protegida.
Ventajas: