Saltar al contenido principal

Estructuras de control

Las estructuras de control son elementos fundamentales en la programación que permiten controlar el flujo de ejecución de un programa. Estas estructuras permiten tomar decisiones, repetir bloques de código y manejar errores (eso último, con try y catch, está en Errores y excepciones).

En JARU, todas las estructuras de control, como if, else, elsif, while, for, etc., deben finalizar con la palabra clave end. Esto indica al compilador que ha llegado al final de la estructura de control. La utilización de end es necesaria para evitar errores sintácticos y para mantener una estructura de código limpia y fácil de entender. Las reglas de los paréntesis y de then están en Sintaxis básica.

Flujo if-then-else​

La estructura de control if-then-else es una de las estructuras de control más básicas en la programación. Se usa para tomar decisiones según una condición. La sintaxis básica es la siguiente:

if (condicion) then
// código a ejecutar si la condición es verdadera
else
// código a ejecutar si la condición es falsa
end

La cláusula elsif es una extensión del if-then-else que permite evaluar varias condiciones en una sola estructura de control. Se ejecuta el primer bloque cuya condición se cumpla:

if (condicion1) then
// código a ejecutar si la condicion1 es verdadera
elsif (condicion2) then
// código a ejecutar si la condicion2 es verdadera
else
// código a ejecutar si ninguna condición anterior es verdadera
end

Flujo switch-case​

La estructura de control switch-case es una forma de controlar el flujo de un programa mediante la selección de diferentes caminos en función de una variable o expresión. Es similar al uso de varias estructuras if-else anidadas, pero tiene la ventaja de ser más legible y fácil de mantener.

switch (variable o expresión)
case valor1:
// instrucciones
case valor2, valor3:
// instrucciones
default:
// instrucciones
end

La expresión se evalúa y se compara con cada uno de los valores case. Si se encuentra una coincidencia, se ejecutan las instrucciones asociadas a ese caso. Si no se encuentra ninguna coincidencia, se ejecutan las instrucciones del default.

func tipoDeDia(dia)
switch (dia)
case 1, 2, 3, 4, 5:
return "laborable"
case 6, 7:
return "fin de semana"
default:
return "no existe"
end
end

println(tipoDeDia(3)) // laborable
println(tipoDeDia(7)) // fin de semana
println(tipoDeDia(9)) // no existe
  • No hay caída de un case al siguiente. Al acabar el bloque de un case, el switch termina: no hace falta break, y tampoco sirve para eso (ver break y continue).
  • Un case admite varios valores, separados por comas: case "A", "a":.
  • Los valores se comparan como con ==. 1 coincide con 1.0, y las cadenas, por su contenido. Una lista, un mapa o un objeto solo coincide consigo mismo, no con otro que tenga lo mismo.
  • Los valores pueden ser expresiones: variables, constantes, enumerados (case Estado.SALTANDO:) o cuentas.
  • Gana el primer case que coincide, en el orden en que están escritos. default solo se ejecuta si no coincide ninguno, aunque esté escrito antes que los case, y solo puede haber uno.
  • Si no coincide ninguno y no hay default, no se ejecuta nada.
  • La expresión va entre paréntesis, y cada case y el default acaban en :.

Con cadenas:

var tecla = "a"
switch (tecla)
case "A", "a":
println("izquierda")
case "D", "d":
println("derecha")
default:
println("otra tecla")
end

Con switch (true), cada case puede ser una condición, y gana la primera que se cumple:

var puntos = 75
switch (true)
case puntos >= 90:
println("Sobresaliente")
case puntos >= 50:
println("Aprobado")
default:
println("Suspenso")
end

Bucle for​

La estructura for en JARU se utiliza para realizar un bucle de manera controlada. La sintaxis básica es la siguiente:

for (inicialización; condición; incremento) 
// cuerpo del bucle
end

La inicialización es la expresión que se ejecuta al principio del bucle; suele ser una variable que se utilizará como contador. La condición es una expresión que se evalúa en cada iteración del bucle: si es falsa, el bucle termina. El incremento es la expresión que se ejecuta al final de cada iteración del bucle.

for (var i = 1; i <= 10; i++) 
println(i)
end

En este ejemplo, la inicialización es var i = 1, la condición es i <= 10, y el incremento es i++. Cada vez que el bucle se ejecuta, se imprime el valor de la variable i y se incrementa en 1.

Bucle infinito

Se puede crear un bucle infinito con for con la siguiente sintaxis:

for (;;)
// cuerpo del bucle
end

Ejemplos de uso de for​

Iterar un número determinado de veces:

for (var i = 0; i < 10; i++)
println("Iteración ", i)
end

Iterar sobre una lista:

var miLista = [1, 2, 3, 4, 5]
for (var i = 0; i < 5; i++)
println("El elemento en la posición ", i, " es ", miLista[i])
end

Iterar en orden inverso:

for (var i = 10; i > 0; i--)
println("Iteración ", i)
end

For extendido​

Una característica única de JARU es su estructura de control for extendida, que agrega funcionalidades de filtro y código alternativo para proporcionar una mayor flexibilidad a los programadores.

La declaración for extendida en JARU sigue la estructura siguiente:

for (var i = valor_inicial; i < valor_final; i = i + incremento; condicion_filtro) 
// código a ejecutar cuando la condición del filtro es verdadera
elfor
// código alternativo a ejecutar cuando la condición del filtro es falsa
end

Análisis de la estructura​

  • Inicialización: var i = valor_inicial; Aquí es donde se inicializa la variable de control del bucle.
  • Condición: i < valor_final; Esta es la condición que se evalúa antes de cada iteración del bucle.
  • Actualización: i = i + incremento; Esta es la operación que se realiza después de cada iteración del bucle.
  • Filtro: condicion_filtro Funcionalidad única de JARU que permite establecer una condición adicional que debe cumplirse para que se ejecute el código dentro del bucle.
  • Código alternativo: elfor Permite especificar un bloque de código alternativo que se ejecutará cuando la condición del filtro no se cumpla.
  • Terminación: end Marca el final del bloque for.

Ejemplos de for extendido​

// Bucle FOR con filtro (solo imprime los números pares)
for (var i = 0; i < 10; i = i + 1; i % 2 == 0)
println(i)
end

// Bucle FOR con filtro y alternativa (imprime "impar" para números impares)
for (var i = 0; i < 10; i = i + 1; i % 2 == 0)
println(i)
elfor
println("impar")
end

Casos de uso del for extendido​

Procesar solo ciertos elementos:

var lista = [1, 2, 3, 4, 5, 6]
for (var i = 0; i < lista.size(); i++; lista[i] % 2 == 0)
println(lista[i])
end

Manejar excepciones o condiciones especiales:

var datos = [10, -3, 25]
for (var i = 0; i < datos.size(); i++; datos[i] >= 0)
println("Procesando ", datos[i])
elfor
println("Dato no válido en el índice: ", i)
end

Bucles anidados con características extendidas:

var usuarios = [
{"nombre": "Ana", "transacciones": [50, 5000]},
{"nombre": "Luis", "transacciones": [20]}
]

for (var i = 0; i < usuarios.size(); i++)
var transacciones = usuarios[i]["transacciones"]
for (var j = 0; j < transacciones.size(); j++; transacciones[j] > 1000)
println("Transacción fraudulenta del usuario ", usuarios[i]["nombre"])
elfor
println("Transacción correcta: ", transacciones[j])
end
end
Consejo

El for extendido es especialmente útil cuando necesitas procesar colecciones de datos con condiciones complejas, evitando tener que anidar múltiples estructuras if dentro del bucle.

Bucle foreach​

La estructura de control foreach en JARU se utiliza para recorrer elementos de una colección, como una lista, un mapa o un array. La sintaxis básica es la siguiente:

foreach (var elemento in coleccion)
// código a ejecutar para cada elemento
end

Donde elemento es una variable temporal que toma el valor de cada uno de los elementos de la colección en cada iteración del bucle. El cuerpo del bucle se ejecuta para cada elemento de la colección.

var lista = [1, 2, 3, 4, 5]
foreach (var numero in lista)
println(numero) // Muestra 1, 2, 3, 4 y 5
end

En este caso, la variable numero toma el valor de cada elemento de la lista en cada iteración, y el código dentro del bloque foreach se ejecuta para cada elemento.

info

El ciclo se detiene automáticamente una vez que se han recorrido todos los elementos de la colección.

Qué recorre foreach en cada tipo (listas, mapas, arrays y cadenas) y cómo cambiar los elementos desde el bucle está en Recorrerlos con foreach.

Bucle while​

La estructura de control while en JARU es un bucle que se ejecuta mientras se cumpla una condición dada. La condición es evaluada al principio de cada iteración, y si es verdadera, el cuerpo del bucle se ejecuta. Si la condición es falsa, el bucle se detiene y se continúa con la siguiente línea de código.

while (condicion)
// Bloque de código a ejecutar
end
Bucle infinito

Si se quiere un bucle infinito con while, lo único que hay que hacer es que la condición sea true:

while (true)
// Bloque de código a ejecutar
end

Ejemplo:

var i = 0
while (i < 10)
println("La variable i tiene el valor ", i)
i += 1
end

En este ejemplo, la condición es i < 10, por lo que el bucle se ejecuta 10 veces, imprimiendo el valor de la variable i en cada iteración.

Importante

Es importante tener cuidado de incluir una forma de detener el bucle, ya sea cambiando la condición dentro del cuerpo del bucle o usando una estructura de control adicional; si no, el bucle se ejecutará indefinidamente.

Bucle until​

El bucle until en JARU se utiliza para repetir un bloque de código hasta que se cumpla una determinada condición.

until (condicion) 
// bloque de código
end

En este código, la condicion es una expresión booleana que se evalúa antes de cada iteración del bucle. Si la condición es falsa, el bloque de código dentro del bucle se ejecutará y luego se volverá a evaluar la condición. Este proceso continuará hasta que la condición sea verdadera, momento en el cual se saldrá del bucle.

Ejemplo que imprime los números del 1 al 10:

var i = 1

until (i > 10)
println(i)
i++
end

Otro ejemplo, una cuenta atrás desde un número hasta cero:

var numero = 10
until (numero == 0)
println(numero)
numero = numero - 1
end
println("¡Despegue!")

Diferencia entre while y until​

Tanto until como while son estructuras de control de flujo que se utilizan para implementar bucles. La principal diferencia está en la forma en que se evalúa la condición de salida del bucle:

  • En until, el bucle se ejecuta hasta que la condición especificada es verdadera
  • En while, el bucle se ejecuta mientras la condición sea verdadera
precaución

Es importante tener en cuenta que el bloque de código dentro del bucle debe modificar la condición de alguna manera para evitar un bucle infinito. De lo contrario, el bucle se ejecutará indefinidamente.

Salir de un bucle: break y continue​

  • break sale del bucle: el programa sigue en la línea de después de su end.
  • continue salta a la vuelta siguiente. En un for, pasa antes por el incremento (i++); en while y until, vuelve a mirar la condición; en foreach, pasa al elemento siguiente.

Valen en for (también en el for extendido), foreach, while y until.

for (var i = 1; i <= 10; i++)
if (i % 2 == 0) then
continue // se salta los pares
end
if (i > 7) then
break // y para al pasar de 7
end
print(i, " ")
end
println()
1 3 5 7

Para buscar algo y dejar de buscar en cuanto aparece:

var nombres = ["Ana", "Luis", "Eva", "Raúl"]
var posicion = -1
for (var i = 0; i < nombres.size(); i++)
if (nombres[i] == "Eva") then
posicion = i
break
end
end
println("Eva está en la posición ", posicion) // Eva está en la posición 2
  • Con bucles anidados, solo afectan al de dentro: un break en el bucle interior no sale del exterior.
  • Dentro de un switch, afectan al bucle que lo contiene. break no sale del switch, sino del bucle:
var ordenes = ["avanza", "gira", "salta", "para", "avanza"]
foreach (var orden in ordenes)
switch (orden)
case "para":
break // sale del foreach, no solo del switch
case "salta":
continue // pasa a la orden siguiente
default:
println("Hago: ", orden)
end
end
println("Fin")
Hago: avanza
Hago: gira
Fin
  • Fuera de un bucle no compilan, con el error «Cannot use 'break' outside of a loop.». Tampoco valen en una función a la que se llama desde un bucle: tienen que estar dentro del propio bucle. Este switch no está en ningún bucle:
var opcion = 1
switch (opcion)
case 1:
println("uno")
break // no compila: no hay ningún bucle
end