Variables estáticas
A veces es necesario describir una variable dentro de una función, asegurando su existencia durante toda la ejecución del programa. Por ejemplo, queremos contar cuántas veces se ha llamado a esta función.
Una variable de este tipo no puede ser local, porque entonces perdería su «memoria larga», pues se creará cada vez que se llame a la función y se eliminará al salir de la misma. Técnicamente, podría describirse de forma global; sin embargo, si la variable sólo se utiliza en esta función, este enfoque es erróneo en términos de diseño del programa.
En primer lugar, una variable global puede modificarse accidentalmente desde cualquier lugar del programa.
En segundo lugar, imagine qué «zoo» de variables se crearía en la región global del programa si declaramos una variable global al menor pretexto. En lugar de ello se recomienda declarar las variables en el bloque más pequeño (si hay varios anidados) en el que se utilicen.
Por lo tanto, el contador de ejecuciones de la función debería describirse dentro de la función. Aquí es donde ayuda el nuevo atributo de las variables, su naturaleza estática.
Una palabra clave especial (modificador), static, colocada antes del tipo de variable en su declaración permite prolongar su vida útil a toda la duración de la ejecución del programa, es decir, la asemeja a las globales. Por regla general, una variable estática sólo se define localmente, en una de las funciones. Por lo tanto, su visibilidad está limitada por el bloque de código correspondiente, como en una variable local normal.
Las variables estáticas también pueden describirse a nivel global, pero no difieren en nada de las globales normales (al menos, en el momento de escribir este libro). Varía con respecto a su comportamiento en C++: allí, su visibilidad está limitada por el archivo en el que se describen. En MQL5, un programa se ensambla sobre la base de un archivo principal mq5 y, tal vez, algunos archivos de cabecera (veáse la directiva#include); por lo tanto, las variables globales estáticas y también las normales están disponibles en todos los archivos fuente del programa.
Una variable estática local se crea sólo una vez: en el momento en que el programa entra por primera vez en la función donde se describe esta variable. Una variable de este tipo sólo se eliminará al descargar el programa. Si una función no se ha invocado nunca, las variables estáticas locales descritas en ella, si las hay, nunca se crearán.
Como ejemplo, modifiquemos la función Greeting de la Parte 1 para que emita saludos diferentes en cada llamada. Póngamosle al nuevo script el nombre GoodTimes.mq5.
Eliminaremos la entrada del script GreetingHour y el parámetro de la función Greeting. Dentro de la función Greeting describiremos una nueva variable estática, counter, de tipo entero, con el valor inicial de 0. Hay que recordar que se trata exactamente de una inicialización, y que se ejecutará una sola vez porque la variable es estática.
string Greeting()
|
Puesto que ahora conocemos el modificador static, es razonable utilizarlo también para el array messages. La cuestión es que antes se declaraba como local, y se volvería a crear cada vez en múltiples llamadas de la función Greeting (y se eliminaría al salir). Esto no es eficiente.
Hay que recordar que un array es un conjunto con nombre de varios valores del mismo tipo, disponibles por índice especificado entre corchetes después del nombre. Gran parte de lo que se ha dicho sobre las variables se aplica directamente a los arrays. Otros matices del trabajo con arrays se abordarán en la sección Arrays.
Pero volvamos a nuestro problema actual. Se elige una opción del array basada en el valor de la variable counter en la sentencia return, y por el momento parece bastante cabalística:
return messages[counter++ % 3]; |
Ya hemos mencionado casualmente la operación de módulo realizada mediante el carácter '%' en la Parte 1. Con ella garantizamos que el índice del elemento no podrá superar el tamaño del array: cualquiera que sea el contador, el módulo (o resto) de la división entre 3 será 0 o 1, o 2.
Lo mismo ocurre con la estructura counter++: significa sumar 1 al valor de la variable (incremento único).
Es importante tener en cuenta que, en esta notación, el incremento se producirá al haber calculado la expresión completa; en este caso, al dividir counter % 3. Esto significa que el recuento comenzará desde cero, es decir, el valor inicial. Existe la posibilidad de hacer un incremento antes de computar la expresión, escribiendo ++counter % 3. En tal caso se empezaría a contar desde 1. Consideraremos las operaciones de este tipo en la sección Incremento y decremento.
Llamemos a la función Greeting desde OnStart 3 veces consecutivas.
void OnStart()
|
Como resultado, veremos las tres cadenas anticipadas con todos los saludos uno tras otro en el registro.
GoodTimes (EURUSD,H1) Good morning, EURUSD
|
Si seguimos llamando a la función, el contador aumentará y los mensajes irán rotando.
Un intento de hacer referencia a la variable counter al final de OnStart (comentado) no permitirá compilar el código, ya que la variable estática, aunque sigue existiendo, sólo está disponible dentro de la función Greeting.
Tenga en cuenta que las llaves se utilizan tanto para formar los bloques de código como para inicializar los arrays. Debe distinguir entre sus aplicaciones. Los arrays se tratarán en detalle en la sección correspondiente. Sin embargo, éstas no son todas las aplicaciones de las llaves: con su uso, aprenderemos más adelante a definir tipos, estructuras y clases personalizados. Las variables estáticas también pueden definirse dentro de estructuras y clases.