ProgramaciónDesarrollador Backend

Describe el mecanismo de rangos numéricos en Kotlin: ¿cómo funcionan Range y Progression, cómo crear rangos personalizados y en qué escenarios son convenientes?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Historia de la pregunta

Desde el principio, Kotlin introdujo rangos (Range) para simplificar las operaciones con conjuntos consecutivos de valores; esto se ha heredado de lenguajes con una sintaxis concisa al trabajar con números (por ejemplo, Python). Además, el mecanismo Range se amplió a Progression, permitiendo especificar el paso de iteración y soportar diferentes tipos de números y caracteres.

Problema

Iterar sobre números enteros, letras, puntos en el tiempo, etc. a menudo requiere una sintaxis especial y un soporte confiable en la biblioteca estándar, de lo contrario, el código se vuelve voluminoso, ilegible y propenso a errores de límites.

Solución

En Kotlin hay tipos estándar IntRange, CharRange y LongRange, así como Progression para la iteración con pasos. Además, se pueden definir rangos para tipos comparables arbitrarios.

// Rango simple for (i in 1..5) print(i) // 12345 // Rango con paso for (i in 1..10 step 2) print(i) // 13579 // Rango inverso for (i in 5 downTo 1) print(i) // 54321 // Rango personalizado (por ejemplo, para Version) data class Version(val major: Int, val minor: Int): Comparable<Version> { override fun compareTo(other: Version): Int = compareValuesBy(this, other, Version::major, Version::minor) } operator fun ClosedRange<Version>.iterator(): Iterator<Version> = object : Iterator<Version> { var current = start override fun hasNext() = current <= endInclusive override fun next() = current.also { current = Version(current.major, current.minor + 1) } } val v1 = Version(1, 0) val v2 = Version(1, 3) for (v in v1..v2) println(v)

Características clave:

  • Sintaxis estándar de rangos: .., downTo, until, step
  • Trabajo con tipos numéricos, de caracteres y personalizados
  • Aplicación en ciclos, comprobación de pertenencia, particiones, validaciones

Preguntas trampa.

¿Cuál es la diferencia entre la expresión 1..5 y 1 until 5?

1..5 incluye ambos extremos del rango: 1,2,3,4,5. 1 until 5 no incluye el último elemento: 1,2,3,4.

¿Se puede definir un rango con un paso menor que cero utilizando step?

No. Para rangos decrecientes, utiliza la construcción downTo, luego step: 5 downTo 1 step 2 (obtendrás 5,3,1).

¿Se pueden utilizar rangos con tipos que no implementan Comparable?

No. Para crear un rango, el tipo debe soportar comparación. De lo contrario, el compilador no permitirá la definición.

Errores típicos y anti-patrones

  • Usar until en lugar de .. o viceversa, confusión con la inclusión de límites
  • Especificar un paso negativo para un rango creciente (step no hace que el rango sea inverso)
  • No cumplir con los requisitos de Comparable para tipos personalizados en el rango

Ejemplo de la vida real

Caso negativo

En el código, en lugar de 1 until n+1, se utilizó 1..n. Obtenemos un elemento adicional, el ciclo excede los límites del rango permitido.

Ventajas:

  • Se captura accidentalmente el caso límite

Desventajas:

  • Errores en particiones, cálculos incorrectos de sumas en los límites

Caso positivo

Se utiliza for (i in 0 until n) para indexar un arreglo de longitud n, el rango coincide exactamente con los valores válidos de los índices.

Ventajas:

  • Se eliminan errores de desbordamiento de arreglos
  • Se mejora la legibilidad

Desventajas:

  • Es necesario recordar la diferencia entre .. y until al cambiar entre lenguajes