Historia de la pregunta:
El subscript es un mecanismo para acceder a valores dentro de colecciones, estructuras y otros tipos mediante corchetes. Se agregó en Swift por analogía a otros lenguajes (por ejemplo, la indexación en arrays de Python, el operador [] en C++/Java), para hacer que trabajar con colecciones y objetos similares sea más intuitivo.
Problema:
No todos los tipos admiten por defecto el acceso a través de índices como un array. Cuando tenemos una estructura o clase con datos, el acceso a los elementos a menudo es más lógico realizarlo a través de una sintaxis familiar (como myObject[index]), en lugar de mediante un método.
Solución:
Swift permite implementar subscript de forma independiente para cualquier tipo personalizado. Se puede hacer tanto para lectura como para escritura. Ejemplo: una estructura que implementa un subscript para trabajar con una matriz cuadrada:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "Índice fuera de rango") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "Índice fuera de rango") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
Características clave:
¿Los subscripts solo pueden usarse para colecciones?
No, los subscripts pueden ser implementados para cualquier tipo: estructura, clase, enum. El tipo de datos dentro no necesita ser necesariamente una colección, lo importante es la lógica de tratamiento de las solicitudes a través del subscript.
¿Se pueden hacer varios subscripts con diferentes firmas en un mismo tipo?
Sí, se permite sobrecargar el subscript con diferentes firmas de parámetros:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
¿Se permite usar un subscript como propiedad computada sin set?
Sí, el subscript puede ser solo de lectura (solo get), entonces cualquier intento de escritura provocará un error de compilación.
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
En una gran estructura se implementó un subscript sin verificación de rango, lo que provoca un fallo de la aplicación al acceder a un índice incorrecto.
Pros:
Contras:
Matrix se implementó con precondición para el rango de índices. Cualquier error se captura de inmediato, no llega a producción.
Pros:
Contras: