Contactos

Introducción a Lúa. Quiere saber todo. Idioma lua Aprender lua desde cero

Recientemente, un amigo cercano fue a una entrevista para un trabajo en una empresa local de desarrollo de juegos. No voy a dar nombres aquí, excepto para decir que era una especie de gran boutique de desarrollo de juegos en Vancouver. No consiguió trabajo, pero hoy no se trata de él. Personalmente, creo que una de las razones fue por su falta de amistad con el lenguaje de programación que utilizan.

Introducción

Estoy en esta área ya que enseño programación de juegos a los estudiantes, pero este es un tema al que no le he prestado suficiente atención en el pasado. Cubrimos Unreal Script como parte del curso "Uso de lo existente". Pero en realidad no consideramos el motor de secuencias de comandos como parte de las utilidades o parte del motor. Entonces, armado con un sitio web, decidí romper esta pequeña barrera. El resultado se describe en este documento.

Lo único es que no estoy seguro de qué tan grande será este documento. Puedo dividirlo en varias partes pequeñas o publicarlo en su totalidad en una larga diatriba de principio a fin. De todos modos, decidiré esto un poco más tarde, cuando formatee mis entradas en un formato más significativo y consistente.

¿Por qué y por qué no?

En primer lugar, ¿por qué usar un lenguaje de secuencias de comandos? La mayor parte de la lógica del juego se puede escribir en un lenguaje de secuencias de comandos para varios propósitos, en lugar de programarse como parte de un motor de juego. Por ejemplo, inicialización de carga o nivel. Después de cargar el nivel, puede que quieras traducir la escena al plan de juego, o puede que quieras mostrar algún texto preliminar. Usando un sistema de secuencias de comandos, puede hacer que ciertos objetos del juego realicen ciertas tareas. Además, considere implementar inteligencia artificial. Los personajes que no son jugadores necesitan saber qué hacer. Programar cada NPC "a mano" en el cuerpo del motor del juego complicaría innecesariamente la tarea. Cuando desee cambiar el comportamiento de un NPC, deberá volver a compilar su proyecto. Con un sistema de secuencias de comandos, puede hacer esto de forma interactiva cambiando el comportamiento y guardando la configuración.

Toqué un poco este problema en el último párrafo, hablaremos más sobre esto un poco más adelante. La pregunta es, ¿por qué no escribir la lógica exclusivamente en C/C++? En pocas palabras, en el futuro, el programador tiene el hecho de que todo cae directamente sobre él y comenzará en consecuencia con el código del juego, al mismo tiempo tendrá que escribir tanto el motor como las utilidades, etc. Pero ahora podemos, con un lenguaje de secuencias de comandos simple, descargar algunas tareas de funcionalidad a los diseñadores de niveles. Pueden comenzar a jugar con el nivel y optimizar el juego. Aquí está el ejemplo real:

Imaginemos que Joe, nuestro desafortunado programador, escribe él mismo todo el motor del juego, las herramientas y la lógica del juego. Sí, Joe lo pasará mal, pero supongamos que no le importa. También tenemos a Brandon, el diseñador del juego. Brandon es un niño bastante inteligente con grandes ideas para el juego. Y así, nuestro codificador, Joe, se arrastra e implementa toda la lógica del juego utilizando el conjunto de herramientas que desarrolló en base al borrador inicial de Brandon. Todo está bien en la oficina. La primera etapa ha terminado y Joe y Brandon están sentados en la sala de juntas y revisan su considerable trabajo. Brandon nota algunos problemas con el juego que no se comporta correctamente. Así que Joe vuelve al código y realiza los cambios necesarios. Este proceso puede llevar un día, al menos si no es un cambio trivial. Luego otro día para recompilar el proyecto. Para no perder un día más, la mayoría de las oficinas dejan el proceso de montaje durante la noche. Entonces, como podemos ver, pasan 24 horas antes de que Brandon vea el cambio que necesitaba.

Ahora, imaginemos que nuestro personaje principal, Joe, decide que la implementación de la lógica del juego utiliza el motor de secuencias de comandos a su favor. Tomará algún tiempo al principio, pero siente que será beneficioso a largo plazo. Y así, cambia algunas funciones del motor del juego al sistema de scripts del juego. También escribe toda la lógica del juego en el sistema de secuencias de comandos mencionado anteriormente. Y así, cuando se encuentra con Brandon y el diseñador nota algo que no coincide con su idea, Joe rápidamente abre la consola, hace algunos cambios en el guión, reinicia el juego y ya ve el nuevo comportamiento. Los cambios se pueden realizar y mostrar inmediatamente en lugar de esperar a que se vuelvan a compilar. Y si Joe fuera especialmente expresivo, el sistema de secuencias de comandos podría usarse para utilidades y estar disponible para los diseñadores de niveles al construir niveles. Si seguimos este camino, entonces, con un poco de entrenamiento, los diseñadores de niveles podrían establecer eventos del juego por sí mismos, como activadores, puertas, otros eventos del juego, y disfrutar de la vida sin forzar al programador.

Este es un ejemplo bastante artificial y puede ser un poco exagerado, pero espero que muestre la diferencia entre los enfoques. Entonces, lo que vamos a intentar hacer con este modelo es avanzar hacia una gestión más automática de los datos. Entonces, esencialmente hacia dónde nos dirigimos:

  1. El codificador está interesado en escribir el código del motor/herramientas, no la lógica del juego.
  2. Se dedicó tiempo a escribir el motor y las herramientas del juego.
  3. A los diseñadores les gusta "jugar" con las cosas. Las secuencias de comandos les dan la libertad de diseñar niveles y funcionalidad. También les da más flexibilidad para experimentar con cosas para las que normalmente traerían a un programador.
  4. No debes volver a compilar si quieres cambiar la funcionalidad del juego. Solo cambia el guión.
  5. Quiere romper el vínculo entre el código de la máquina y el código del juego. Deben ser dos partes separadas. Así, será conveniente usar el motor para posteriores secuelas (espero).

Aquí haré algunas predicciones. Dentro de 5 años, los diseñadores de niveles tendrán que hacer algo más que construir niveles. Deben poder usar el guión para las escenas del juego. Varias empresas con visión de futuro ya han adoptado este enfoque. Además, puede ver este tipo de integración en editores como UnrealEd y el conjunto de herramientas Aurora Bioware.

Explicación y retórica

Espero que ya hayas creído mis palabras y hayas querido incluir un componente de script en tu juego. Y entonces, la siguiente pregunta es: ¿cómo diablos lo haces?

Lo que voy a usar para mi componente de script es un motor de script inyectable. Lúa. De entrada diré que no soy un experto en lua, pero es un lenguaje relativamente sencillo y no requiere un aprendizaje tedioso para dominarlo. Algunos de los siguientes ejemplos, que analizaré, son bastante simples. Al final de este documento, voy a incluir algunos antecedentes adicionales. Para ser justos, hay otros lenguajes de secuencias de comandos, como Small, Simkin, Python, Perl. Sin embargo, Lua es un lenguaje agradable y limpio. Este es un muy buen beneficio.

Lua es de código abierto. Esto es bueno porque: (a) obtienes la fuente del idioma y puedes hurgar en él todo lo que quieras, (b) es gratis. Puede usarlo en aplicaciones comerciales sin tirar el dinero. Bueno, para proyectos no comerciales, entiendes gratis == bien.

Entonces, ¿quién está usando Lua actualmente? ¿Lua está escrito por un escritorio sharashka y solo los pobres lo usan? Mmmm... no realmente. Lua no apareció ayer y fue utilizada por personalidades bastante famosas:

  • lucasarts
    • Fandango sombrío
    • Escapar de la isla de los monos
  • bioware
    • Nunca noches de invierno

Ok, suficiente con el quién es quién de los desarrolladores de lua. Puedes verlo por ti mismo en el sitio web de lua.

Comencemos realmente simple. Lo primero que debemos construir nos mostrará cómo se usa el intérprete lua. Lo que se requiere para esto:

  1. Obtener el código del intérprete de Lua.
  2. Configuración de su entorno de desarrollo.
  3. Construyendo un intérprete desde cero.

Oye, pensé que habías dicho basta de despotricar.

Bueno, ¿es eso suficiente? Entonces, pongámonos manos a la obra. Puede obtener todo el código fuente de Lua en el sitio web oficial. También me gustaría tomarme un segundo y llamar su atención sobre el hecho de que hay una nueva versión de lua 5.0 en el horizonte. No voy a discutir esta versión en este artículo. Me ocuparé de eso más tarde, pero por ahora, usaremos 4.0.1.

Lo primero que haremos será construir la biblioteca lua. De esta manera no necesitamos incluir las fuentes cada vez que construimos el proyecto. No es difícil y este no es el propósito de nuestras lecciones. Por lo tanto, incluí la biblioteca de antemano como parte de este artículo. Usé una biblioteca estática para este ejemplo. Sí, tal vez lo construiría como una DLL, pero para un sistema de secuencias de comandos, una biblioteca estática es un poco más rápida. Tenga en cuenta, no mucho, pero más rápido.

Nuestro invitado de hoy es un verdadero luchador del frente oculto. Es posible que lo hayas visto en juegos (World of Warcraft, Angry Birds, X-Plane, S.T.A.L.K.E.R.) o productos de Adobe (Lightroom), pero ni siquiera pensaste en su existencia. Mientras tanto, este idioma tiene casi 25 años y todo este tiempo ha hecho que nuestra vida virtual sea un poco mejor.

Breve información

Lua habría sido acuñado en 1993 en la Universidad Católica de Río de Janeiro. El nombre se traduce del portugués como la Luna, y los creadores le piden amablemente que no escriba LUA, para que, Dios no lo quiera, alguien tome el nombre como una abreviatura. Es un lenguaje de secuencias de comandos multiparadigma que utiliza el modelo OOP prototípico.

La escritura aquí es dinámica y las metatablas se utilizan para implementar la herencia, es decir, esta es una gran herramienta para ampliar las capacidades de su producto. Y debido a su tamaño compacto, es adecuado para su uso en casi cualquier plataforma. Juzgue usted mismo: el tarball Lua 5.3.4 pesa solo 296 kilobytes (sin comprimir, 1,1 megabytes), el intérprete (escrito en C) para Linux, de 182 a 246 kilobytes, y el conjunto estándar de bibliotecas, otros 421 kilobytes.

El código

En apariencia y características, Lua parece otro intento de rehacer JavaScript, si no fuera por el hecho de que este último apareció dos años después. Ver por ti mismo:

Empecemos por lo tradicional:

imprimir("Hola mundo")

De acuerdo, familiar y no demasiado informativo. Un ejemplo más interesante desde el punto de vista de la familiaridad con Lua es calcular el factorial de un número de entrada:

Función hecho(n)
si n == 0 entonces
volver 1
demás
devolver n * hecho(n-1)
final
final

Imprimir("ingrese un numero:")
a = io.read("*número") -- leer un número
imprimir (hecho (a))

Todo está muy claro. Por cierto, Lua admite la asignación en paralelo:

Y en conclusión, un ejemplo bastante simple usando bibliotecas:

#incluir
#incluir
#incluir
#incluir
#incluir

int principal (vacío) (
beneficio de carbón;
en terror;
estado_lua *L = lua_open(); /* abre Lua */
luaopen_base(L); /* abre la biblioteca básica */
luaopen_table(L); /* abre la biblioteca de tablas */
luaopen_io(L); /* abre la biblioteca de E/S */
luaopen_string(L); /* abre la cadena lib. */
luaopen_math(L); /* abre la biblioteca matemática. */

Mientras (fgets(buff, sizeof(buff), stdin) != NULL) (
error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
lua_pcall(L, 0, 0, 0);
si (error) (
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1); /* mensaje de error emergente de la pila */
}
}

Lua_cerrar(L);
devolver 0;
}

Ventajas y desventajas

Entonces, ¿qué tiene de bueno Lua?

En primer lugar, como ya se ha señalado, su compacidad y, junto con el hecho de que el código fuente está escrito en C, obtiene una interacción completa con uno de los lenguajes más populares del planeta y una amplia gama de plataformas disponibles.

Entornos de desarrollo

LDT (Lua Development Tools) para Eclipse: una extensión para uno de los IDE más populares;

ZeroBrane Studio es un entorno especializado escrito en Lua;

Decoda no es el IDE multiplataforma más popular, pero es una alternativa;

SciTE es un buen editor que soporta completamente Lua;

WoWUIDesigner: ¿adivina para qué juego ayuda este entorno a procesar scripts, incluidos los de Lua?

Enlaces útiles

http://www.lua.org/home.html - sitio oficial con toda la información necesaria, tutoriales, libros, documentación e incluso algo de humor específico;

http://tylerneylon.com/a/learn-lua/ - gran tutorial de Tyler Neylon. Adecuado para programadores con experiencia que conocen bien el inglés (sin embargo, tampoco habrá grandes problemas con el diccionario) y solo quieren expandir sus horizontes;

https://zserge.wordpress.com/2012/02/23/lua-in-60-minutes/ - los conceptos básicos de Lua en 60 minutos de un programador que obviamente no es indiferente a este lenguaje. En ruso;

http://lua-users.org/wiki/LuaTutorial - tutorial wiki;

https://youtube.com/watch?v=yI41OL0-DWM- Tutoriales en video de YouTube que lo ayudarán a comprender visualmente la configuración del IDE y los principios básicos del lenguaje.

guiones lua

Un script escrito en Lua no tiene ninguna función especial desde la cual comenzaría su ejecución. Un script puede verse simplemente como un conjunto de comandos (instrucciones) que se ejecutan a partir de la primera instrucción.

El script puede ser muy simple, que consiste en un solo comando, o muy complejo, que contiene decenas, cientos o incluso miles de instrucciones. Las siguientes instrucciones pueden estar separadas por un punto y coma (;). Sin embargo, este requisito no es obligatorio, por lo que todo el código siguiente es correcto en términos de sintaxis:

Trabajando con variables en Lua

Las variables se utilizan para almacenar valores durante la ejecución del script.

Nombres de variables en Lua

Los nombres de variables (identificadores) en Lua pueden ser cualquier secuencia de letras, números y guiones bajos que no comiencen con un número.

Nota

El lenguaje Lua distingue entre mayúsculas y minúsculas, por lo que abc, Abc, ABC son nombres diferentes.

La siguiente tabla enumera las palabras que están reservadas por el idioma Lua y no se pueden usar en nombres de variables:

y romper hacer otra cosa otra cosa si

fin falso para la función si

en local cero no o

repetir volver luego verdadero hasta

Además, todos los nombres que comienzan con un guión bajo seguido de una letra mayúscula (por ejemplo, _VERSION) también están reservados.

¿Cuáles son las variables en Lua?

Las variables en Lua pueden ser globales o locales. Si una variable no se declara explícitamente local, se considera global.

Variables globales de Lua

Una variable global aparece en el momento en que se le asigna su primer valor. Antes de asignar el primer valor, acceder a una variable global arroja cero.

MsgBox(tostring(g)) --> nil

MsgBox(acadena(g)) --> 1

La variable global existe mientras exista el entorno de ejecución del script y esté disponible para cualquier código Lua que se ejecute en este entorno.

Si es necesario, puede eliminar explícitamente una variable global simplemente configurándola en cero.

g = 1 - crea una variable global g con valor 1

g = nil - elimina la variable global g

MsgBox(tostring(g)) --> nil

Todas las variables globales son campos en una tabla regular llamada entorno global. Esta tabla está disponible a través de la variable global _G. Dado que los campos del entorno global son todas variables globales (incluida la propia _G), entonces _G._G == _G.

Variables locales de Lua

Cualquier variable local debe declararse explícitamente usando la palabra clave local. Puede declarar una variable local en cualquier parte del script. La declaración puede incluir la asignación de un valor inicial a la variable. Si no se asigna ningún valor, la variable contiene cero.

local a - declara la variable local a

local b = 1 - declara la variable local b, asígnale el valor 1

local c, d = 2, 3 - declara las variables locales c y d, asígnales los valores 2 y 3

El alcance de una variable local comienza después de la declaración y continúa hasta el final del bloque.

Nota

El alcance de una variable es una sección del código del programa dentro del cual puede acceder al valor almacenado en esta variable.

Bloque significa:

cuerpo de la estructura de control (if-then, else, for, while, repeat);

cuerpo funcional;

un fragmento de código encerrado en las palabras clave do...end.

Si una variable local se define fuera de cualquier bloque, su alcance se extiende hasta el final del script.

local i = 1 - la variable i es local dentro del script

mientras yo<= a do - цикл от 1 до 5

local a = i^2 - la variable a es local dentro del bucle while

Cuadro de mensaje (a) --> 1, 4, 9, 16, 25

Cuadro de mensaje(a) -->

si i > 5 entonces

local a - variable a es local dentro entonces

Cuadro de mensaje (a) --> 10

MsgBox(a) --> 5 (refiriéndose a global a aquí)

local a = 20 - la variable a es local dentro del do-end

Cuadro de mensaje (a) --> 20

MsgBox(a) --> 5 (refiriéndose a global a aquí)

Nota

Siempre que sea posible, se recomienda utilizar variables locales en lugar de globales. Esto evitará contaminar el espacio de nombres global y proporcionará un mejor rendimiento (porque acceder a las variables locales en Lua es un poco más rápido que acceder a las globales).

Tipos de datos Lua

¿Qué tipos de datos admite el lenguaje Lua?

Lua admite los siguientes tipos de datos:

1. Nil (nada). Corresponde a la ausencia de un valor para una variable. Este tipo está representado por un solo valor, nil.

2. Booleano (lógico). Este tipo incluye los valores falso (falso) y verdadero (verdadero).

Al realizar operaciones lógicas, el valor nil se trata como falso. Todos los demás valores, incluido el número 0 y la cadena vacía, se tratan como verdaderos.

3. Número (numérico). Se utiliza para representar valores numéricos.

Las constantes numéricas pueden tener una parte fraccionaria opcional y un exponente decimal opcional especificado por los caracteres "e" o "E". Las constantes numéricas enteras se pueden especificar en hexadecimal utilizando el prefijo 0x.

Ejemplos de constantes numéricas válidas: 3, 3.0, 3.1415926, 314.16e-2, 0xff.

4. Cuerda (cadena). Se utiliza para representar cadenas.

Los valores de cadena se especifican como una secuencia de caracteres entre comillas simples o dobles:

a = "esto es una cadena"

b = "esta es la segunda línea"

Las cadenas entre comillas dobles pueden interpretar secuencias de escape tipo C que comienzan con un carácter "\" (barra invertida):

\b (espacio),

\n (salto de línea),

\r (retorno de carro);

\t (pestaña horizontal),

\\ (barra invertida);

\"" (comillas dobles);

\" (una frase).

Nota

Un carácter en una cadena también se puede representar por su código usando la secuencia de escape:

donde ddd es una secuencia de no más de tres dígitos.

Además de las comillas, también se pueden usar corchetes dobles para definir una cadena:

Definir una cadena con corchetes dobles le permite ignorar todas las secuencias de escape, es decir, la cadena se crea completamente como se describe:

local a = [] en Lua]=]

Habrá un término: "definición de cadena [] en Lua"

5. Función (función). Las funciones en Lua pueden escribirse en variables, pasarse como parámetros a otras funciones y devolverse como resultado de la ejecución de funciones.

6. Mesa (mesa). Una tabla es un conjunto de pares "clave" - ​​"valor", que se denominan campos o elementos de una tabla. Tanto las claves como los valores de los campos de la tabla pueden ser de cualquier tipo excepto nil. Las tablas no tienen un tamaño fijo: en cualquier momento, puede agregarles un número arbitrario de elementos.

Lea más en el artículo "Creación de tablas en Lua"

7. Datos de usuario (datos de usuario). Es un tipo de dato especial. Los valores de este tipo no se pueden crear ni modificar directamente en un script de Lua.

Los datos de usuario se usan para representar nuevos tipos creados en el llamador del script o en bibliotecas escritas en C. Por ejemplo, las bibliotecas de extensión de Lua para "CronosPRO" usan este tipo para representar objetos como:

bancos de datos (clase de banco);

bases de datos (clase Base);

registros (registro de clase), etc.

8. Hilo (hilo). Corresponde al flujo de ejecución. Estos subprocesos no están conectados de ninguna manera al sistema operativo y son compatibles exclusivamente con el propio Lua.

¿Cómo establecer el tipo de una variable en Lua?

Lua no especifica explícitamente el tipo de una variable. El tipo de una variable se establece en el momento en que se asigna un valor a la variable. A cualquier variable se le puede asignar un valor de cualquier tipo (independientemente del tipo que contenía anteriormente).

a = 123 - la variable a tiene número de tipo

a = "123" - ahora la variable a es de tipo cadena

a = verdadero - la variable a ahora es de tipo booleano

a = () - ahora la variable a es de tipo tabla

Nota

Las variables de tipo tabla, función, hilo y datos de usuario no contienen los datos en sí, pero almacenan referencias a los objetos correspondientes. Al asignar, pasar a una función como argumento y regresar de una función como resultado, los objetos no se copian, solo se copian las referencias a ellos.

a = () - crea una tabla. Se coloca una referencia a la tabla en la variable a

b = a - la variable b se refiere a la misma tabla que a

a = 10 - al elemento de tabla con índice 1 se le asigna el valor 10

Cuadro de mensaje (b) --> "10"

Cuadro de mensaje (a) --> "20"

El resto de los datos son valores inmediatos.

Cuadro de mensaje (a) --> "20"

Cuadro de mensaje (b) --> "10"

¿Cómo obtener el tipo de una variable en Lua?

El tipo de un valor almacenado en una variable se puede averiguar utilizando el tipo de función estándar. Esta función devuelve una cadena que contiene el nombre del tipo ("nil", "number", "string", "boolean", "table", "function", "thread", "userdata").

t = tipo ("esto es una cadena") - t es igual a "cadena"

t = tipo (123) - t es "número"

t = tipo(tipo) - t es igual a "función"

t = tipo (verdadero) - t es "booleano"

t = tipo (nil) - t es "nil"

t = tipo (CroApp.GetBank()) - t es igual a "datos de usuario"

¿Cómo convertir el tipo de una variable en Lua?

Lua convierte automáticamente números en cadenas y viceversa, si es necesario. Por ejemplo, si un valor de cadena es un operando en una operación aritmética, se convierte en un número. Del mismo modo, un valor numérico que se encuentre donde se espera una cadena se convertirá en una cadena.

a = "10" + 2 - a es igual a 12

a = "10" + 2 - a es igual a "10 + 2"

a = "-5.3e-10"*"2" - a es igual a -1.06e-09

a = "cadena" + 2 - ¡Error! No se puede convertir "cadena" a número

Un valor de cualquier tipo se puede convertir explícitamente en una cadena mediante la función tostring estándar.

a = tostring(10) - a es "10"

a = tostring(verdadero) - a es igual a "verdadero"

a = tostring(nil) - a es igual a "nil"

a = tostring (( = "este es el campo 1")) - a es igual a "tabla: 06DB1058"

En el ejemplo anterior, puede ver que la función tostring no convierte el contenido de las tablas. Esta transformación se puede hacer usando la función render.

a = representar (10) - a es "10"

a = render (verdadero) - a es igual a "verdadero"

a = render(nil) - a es "nil"

a = representar (( = "este es el campo 1")) - a es "( = "este es el campo 1")"

Para convertir explícitamente un valor en un número, puede usar la función tonumber estándar. Si el valor es una cadena que se puede convertir en un número (o ya es un número), la función devuelve el resultado de la conversión; de lo contrario, devuelve nil.

a = tonumber("10") - a es igual a "10"

a = tonumber("10..5") - a es igual a 10.5

a = tonumber(true) - a es igual a "nil"

a = tonumber (nil) - a es igual a "nil"

Arreglo de comentarios en Lua

Un comentario en Lua comienza con dos signos menos (--) y continúa hasta el final de la línea.

local a = 1 - comentario de una sola línea

Si dos corchetes de apertura ([[) siguen inmediatamente a los caracteres "--", el comentario es de varias líneas y continúa hasta los dos corchetes de cierre (]]).

local a = 1 - [[ multilínea

un comentario ]]

Los corchetes dobles en los comentarios se pueden anidar. Para no confundirlos, se inserta un signo igual (=) entre paréntesis:

local a = [[Compañía Kronos]] - [=[

local a = [[Compañía Kronos]]

El número de caracteres "=" determina el anidamiento:

local a = [=[definición de alguna cadena [] en Lua]=] --[==[

local a = [=[definición de alguna cadena [] en Lua]=]

Operaciones utilizadas en Lua

En expresiones escritas en Lua, se pueden utilizar los siguientes tipos de operaciones:

1. Operaciones aritméticas.

Lua admite las siguientes operaciones aritméticas:

+ (suma);

- (resta);

* (multiplicación);

/ (división);

^ (exponenciación);

% (resto de la división).

Nota

Las operaciones aritméticas son aplicables tanto a números como a cadenas, que en este caso se convierten en números.

2. Operaciones de comparación.

Las siguientes operaciones de comparación de valores están permitidas en Lua:

== (igual a);

~= (no igual);

< (меньше);

> (mayor);

<= (меньше или равно);

>= (mayor o igual que).

Nota

Las operaciones de comparación siempre devuelven el valor booleano verdadero o falso.

Las reglas para convertir números en cadenas (y viceversa) no funcionan durante las comparaciones, es decir, la expresión "0" == 0 da como resultado falso.

3. Operaciones lógicas.

Las operaciones lógicas son:

y (AND lógico).

El operador and devuelve su primer operando si se evalúa como falso o nulo. De lo contrario, la operación devuelve el segundo operando (y este operando puede ser de cualquier tipo).

a = (cero y 5) - a es igual a cero

a == (falso y 5) - a es falso

a == (4 y 5) - a es igual a 5

o (OR lógico).

El operador or devuelve el primer operando si no es falso ni nulo, de lo contrario, devuelve el segundo operando.

a == (4 o 5) - a es igual a 4

a == (falso o 5) - a es igual a 5

Nota

Las operaciones lógicas and y or pueden devolver valores de cualquier tipo.

Las operaciones lógicas y y o evalúan el valor del segundo operando solo si es necesario devolverlo. Si no es necesario, el segundo operando no se evalúa. Por ejemplo:

a == (4 o f()) - la función f() no será llamada

no (NO lógico).

El operador not siempre devuelve verdadero o falso.

4. Operación de concatenación.

Para concatenar (combinar) cadenas, use la operación ... (dos puntos).

a = "Kronos".."-".."Inform" - la variable a obtendrá el valor "Kronos-Inform"

Nota

Si uno o ambos operandos son números, se convierten en cadenas.

a = 0..1 - la variable a obtendrá el valor "01"

5. La operación de obtener la longitud.

Lua define el operador de longitud #, que se puede usar para obtener la longitud de una cadena.

a = "cadena"

len = #a - len es igual a 6

len = #"una línea más" - len es 10

Nota

También puede usar el operador # para averiguar el índice máximo (o tamaño) de una matriz. Para obtener más detalles, consulte el artículo "Trabajar con arreglos en Lua".

Precedencia de operadores en Lua

En Lua, las operaciones se realizan según la siguiente precedencia (en orden descendente):

2. no # - (unario)

6. < > <= >= ~= ==

Llamar scripts desde formularios

Cada formulario (incluidos los formularios anidados) tiene un script separado asociado, que normalmente contiene funciones que manejan los eventos del formulario y sus elementos.

Cuando se ejecuta un formulario, su script se carga en el entorno global. Cuando ocurre un evento de un formulario o su elemento, el sistema llama a la función de controlador asociada con este evento.

Cabe señalar que el script de formulario, aunque no contiene una llamada a la función de módulo, en realidad es un módulo. Esto significa que las variables declaradas en el script de formulario sin la palabra clave local no están expuestas al entorno global y solo están disponibles dentro de este script. Si un valor debe estar disponible para otros scripts de formulario, debe definirse explícitamente en la tabla _G global:

local a = _G.var

Bloques de sentencias (instrucciones)

Los principales operadores de Lua son:

asignación;

operador condicional;

Operadores para la organización de ciclos.

Un grupo de sentencias se puede combinar en un bloque (sentencia compuesta) usando la construcción do...end.

hacer - el comienzo del bloque

<оператор1>- cuerpo de bloque

<оператор2>

<операторN>

final - el final del bloque

El bloque abre un nuevo ámbito donde puede definir variables locales.

a = 5 - variable global a

local a = 20 - la variable local a se define dentro de do-end

Cuadro de mensaje (a) --> 20

MsgBox(a) --> 5 (aquí la referencia ya es a la global a)

Operador de asignación en Lua

Una asignación cambia el valor de una variable o campo de tabla. En su forma más simple, una tarea podría verse así:

a = 1 - a la variable a se le asigna el valor 1

a = b + c - a la variable a se le asigna la suma de los valores de las variables b y c

a = f(x) - a la variable a se le asigna el valor devuelto por la función f(x)

En Lua se permite la llamada asignación múltiple, cuando varias variables a la izquierda del operador de asignación reciben los valores de varias expresiones escritas a la derecha del operador de asignación:

a, b = 1, 5*c - a es igual a 1; b es igual a 5*c

Si hay más variables que valores, las variables "extra" se asignan a cero.

a, b, c = 1, 2 - a es igual a 1; b es 2; c es igual a cero

Si hay más valores que variables, los valores "extra" se ignoran.

a, b = 1, 2, 3 - a es igual a 1; b es 2; valor 3 no utilizado

Se puede utilizar la asignación múltiple para intercambiar valores entre variables:

a = 10; b = 20 - a es 10, b es 20

a, b = b, a - ahora a es 20, b es 10

Declaración condicional (si) en Lua

La declaración if prueba la verdad de una condición dada. Si la condición es verdadera, se ejecuta la parte del código que sigue a la palabra clave "then" (sección "then"). De lo contrario, se ejecuta el código que sigue a la palabra clave else (sección else).

si a > b entonces

devuelve a - si a es mayor que b, devuelve a

devolver b - de lo contrario, devolver b

La sección else es opcional.

si un< 0 then

a = 0 - si a es menor que 0, establezca a en 0

Puede usar la construcción elseif en lugar de declaraciones if anidadas. Por ejemplo, el siguiente código:

será más fácil de leer si lo reemplaza con lo siguiente:

devuelve "Ivan" - si a es igual a 1

elseif a == 2 entonces

devuelve "Peter" - si a es 2

elseif a == 3 entonces

devuelve "Sergey" - si a es igual a 3

devolver "No such player" - si a no es ninguno de los enumerados

Bucle con condición previa (mientras) en Lua

La instrucción while está diseñada para organizar ciclos con una condición previa y tiene la siguiente forma:

tiempo hacer

... - cuerpo de bucle

Antes de cada iteración del bucle, se comprueba la condición :

si la condición es falsa, el ciclo termina y el control se transfiere a la primera instrucción que sigue a la instrucción while;

si la condición es verdadera, se ejecuta el cuerpo del ciclo, después de lo cual se repiten todas las acciones.

while i > 0 do - ciclo de 10 a 1

t[i] = "campo"..i

a = (3, 5, 8, -6, 5)

while i > 0 do - busque un valor negativo en la matriz

si un [yo]< 0 then break end - если найдено, прерываем цикл

i = i - 1 - de lo contrario, vaya al siguiente elemento

si i > 0 entonces

MsgBox("Índice de valor negativo: "..i)

MsgBox("La matriz no contiene valores negativos")

Nota

Bucle con poscondición (repetición) en Lua

El operador de repetición está diseñado para organizar ciclos con una condición posterior y tiene la siguiente forma:

... - cuerpo de bucle

Hasta que

El cuerpo del ciclo se ejecuta hasta que la condición no se hará realidad. La condición se verifica después de la ejecución del cuerpo del bucle, por lo que, en cualquier caso, el cuerpo del bucle se ejecutará al menos una vez.

Sume los valores de la matriz a hasta que la suma exceda 10

a = (3, 2, 5, 7, 9)

suma = suma + a[i]

hasta suma > 10

MsgBox("Se agregaron ..i.." elementos. La suma es igual a "..sum)

Puede usar la instrucción break para salir de un bucle antes de que finalice.

Nota

Para obtener más información sobre las características del uso de la declaración de ruptura, consulte el artículo "Declaraciones de ruptura y devolución"

Bucles con una instrucción for en Lua

La declaración for está diseñada para organizar bucles y permite dos formas de escritura:

simple (numérico para);

extendido (universal para).

La forma simple de la instrucción for

La forma simple de la instrucción for es la siguiente:

para var = exp1, exp2, exp3 hacer

... - cuerpo de bucle

El cuerpo del bucle se ejecuta para cada valor de la variable de bucle (contador) var en el rango de exp1 a exp2, con un paso de exp3.

Nota

Es posible que no se especifique el paso. En este caso, se toma igual a 1.

for i = 1, 10 do - bucle de 1 a 10 con el paso 1

MsgBox("i es igual a"..i)

for i = 10, 1, -1 do - ciclo de 10 a 1 con paso -1

MsgBox("i es igual a"..i)

Nota

Las expresiones exp1, exp2 y exp3 se evalúan una sola vez, antes del inicio del bucle. Entonces, en el ejemplo a continuación, se llamará a la función f(x) para calcular el límite superior del ciclo solo una vez:

for i = 1, f(x) do - bucle de 1 al valor devuelto por f()

MsgBox("i es igual a"..i)

La variable de bucle es local para la sentencia de bucle y no está definida al final del bucle.

for i = 1, 10 do - bucle de 1 al valor devuelto por f()

MsgBox("i es igual a"..i)

MsgBox("Después de salir del ciclo, i es "..i") - ¡Incorrecto! es igual a cero

Nota

El valor de una variable de bucle no se puede cambiar dentro del bucle: las consecuencias de tal cambio son impredecibles.

La instrucción break se usa para salir del ciclo antes de que se complete.

a = (3, 5, 8, -6, 5)

for i = 1,#a do - busque un valor negativo en la matriz

si un [yo]< 0 then - если найдено...

index = i - guarda el índice del valor encontrado...

romper - y romper el ciclo

MsgBox("Índice de valor negativo: "..index)

Nota

Para obtener más información sobre las características del uso de la declaración de ruptura, consulte el artículo "Declaraciones de ruptura y devolución")

Soy un programador sentimental. A veces me enamoro de los lenguajes de programación y luego puedo hablar de ellos durante horas. Compartiré una de estas horas contigo.

lúa? ¿Qué es esto?

Lua es un lenguaje embebible simple (se puede integrar con tus programas escritos en otros lenguajes), liviano y comprensible, con un solo tipo de datos, con una sintaxis uniforme. El idioma perfecto para aprender.

¿Para qué?

Lua te puede ser útil:

* si eres un jugador (complementos para World of Warcraft y muchos otros juegos)
* si escribe juegos (muy a menudo en juegos, el motor está escrito en C / C ++ y AI - en Lua)
* si es programador de sistemas (puede escribir complementos para nmap, wireshark, nginx y otras utilidades en Lua)
* si eres un desarrollador integrado (Lua es muy rápido, compacto y requiere muy pocos recursos)

1. Aprende a programar. Al menos un poco. No importa el idioma.
2. Instale Lua. Para ello, descargue la versión 5.2 aquí (http://www.lua.org/download.html), o búsquela en los repositorios. La versión 5.1 también funcionará, pero tenga en cuenta que es muy antigua.

Ejecute todos los ejemplos del artículo en la terminal con un comando como "lua file.lua".

Primeras impresiones

Lua es un lenguaje tipado dinámicamente (las variables obtienen tipos sobre la marcha dependiendo de los valores asignados). Puede escribir en él tanto en estilo imperativo como orientado a objetos o funcional (incluso si no sabe cómo es, está bien, siga leyendo). Aquí está Hello world en Lua:

Mi primera aplicación lua: hello.lua print "hola mundo"; imprimir("adios mundo")

Lo que se puede decir sobre el idioma:

* los comentarios de una sola línea comienzan con dos guiones "--"
* se pueden omitir los corchetes y los puntos y comas

Operadores de lenguaje

El conjunto de declaraciones condicionales y bucles es bastante típico:

Declaraciones condicionales (puede que no haya una rama else) if a == 0 then print("a is zero") else print("a is not zero") end -- forma abreviada if/elseif/end (en lugar de switch/ case) if a == 0 then print("cero") elseif a == 1 then print("uno") elseif a == 2 then print("dos") else print("otro") end -- count loop for i = 1, 10 do print(i) end -- ciclo con condición previa b = 5 while b > 0 do b = b - 1 end -- ciclo con condición posterior repetir b = b + 1 hasta que b >= 5

PIENSA: ¿qué podría significar el bucle "for i = 1, 10, 2 do... end"?

En las expresiones, puede utilizar los siguientes operadores en las variables:

* asignación: x = 0
* aritmética: +, -, *, /, % (resto), ^ (exponenciación)
* lógico: y, o, no
* comparación: >,<, ==, <=, >=, ~= (no-igual, sí-sí, en lugar del habitual "!=")
* concatenación de cadenas (operador ".."), por ejemplo: s1="hola"; s2="mundo"; s3=s1..s2
* longitud/tamaño (operador #): s="hola"; a = #s ('a' será igual a 5).
* obtener elemento por índice, por ejemplo: s

Durante mucho tiempo no hubo operaciones de bits en el lenguaje, pero en la versión 5.2 apareció la librería bit32, que las implementa (como funciones, no como operadores).

Tipos de datos

Te mentí cuando dije que el idioma tiene un tipo de datos. Tiene muchos de ellos (como todo lenguaje serio):

* nil (absolutamente nada)
* números booleanos (verdadero/falso)
* números (números) - sin división en números enteros / reales. Solo números.
* cadenas - por cierto, son muy similares a las cadenas en pascal
* funciones - sí, la variable puede ser del tipo "función"
* hilo
* datos arbitrarios (datos de usuario)
* mesa

Si todo está claro con los primeros tipos, ¿qué son los datos de usuario? Recuerde que Lua es un lenguaje integrable y por lo general trabaja de cerca con componentes de programas escritos en otros lenguajes. Por lo tanto, estos componentes "extranjeros" pueden crear datos para sus propias necesidades y almacenar estos datos junto con objetos lua. Por lo tanto, los datos de usuario son la parte submarina del iceberg que, desde el punto de vista del idioma lua, no es necesaria, pero simplemente no podemos ignorarla.

Y ahora lo más importante en el idioma - tablas.

mesas

Te mentí de nuevo cuando dije que el idioma tiene 8 tipos de datos. Puedes considerar que es uno: todo son tablas (esto, por cierto, tampoco es cierto). Una tabla es una estructura de datos muy elegante, combina las propiedades de una matriz, una tabla hash ("clave" - ​​"valor"), una estructura, un objeto.

Entonces, aquí hay un ejemplo de una tabla como matriz: a = (1, 2, 3) -- una matriz de 3 elementos print(a) -- imprime "2" porque los índices se cuentan desde uno -- Y el la tabla tiene la forma de una matriz dispersa (que no tiene todos los elementos) a = () -- tabla vacía a = 1 a = 5

PIENSE: ¿qué es a en el caso de una matriz dispersa?

En el ejemplo anterior, la tabla se comporta como una matriz, pero en realidad tenemos claves (índices) y valores (elementos de matriz). Y al mismo tiempo, las claves pueden ser de cualquier tipo, no solo números:

A = () a["hola"] = verdadero a["mundo"] = falso a = 1 -- o así: a = (hola = 123, mundo = 456) print(a["hola")) print (a.hello) es lo mismo que a["hello"], aunque parece una estructura con campos

Por cierto, dado que la tabla tiene claves y valores, puede recorrer todas las claves y sus valores correspondientes en un bucle:

T = (a = 3, b = 4) para clave, valor en pares (t) imprime (clave, valor) -- imprimirá "a 3", luego "b 4" final

Pero, ¿y los objetos? Aprenderemos sobre ellos un poco más tarde, primero, sobre funciones.

Funciones

Aquí hay un ejemplo de una función regular.

Función sumar(a, b) devuelve a + b end print(suma(5, 3)) -- imprime "8"

Las funciones de lenguaje le permiten tomar múltiples argumentos y devolver múltiples argumentos. Por lo tanto, los argumentos cuyos valores no se especifican explícitamente se consideran iguales a cero.

PIENSE: ¿por qué querría devolver múltiples argumentos?

Función swap(a, b) return b, a end x, y = swap(x, y) -- por cierto, esto se puede hacer sin una función: x, y = y, x -- y si la función devuelve múltiples argumentos, -- no los necesita - ignórelos con -- la variable de subrayado especial "_" a, _, _, d = alguna_función()

Las funciones pueden tomar un número variable de argumentos:

En el prototipo, un número variable de argumentos se escribe como función de puntos suspensivos sum(...) s = 0 para _, n en pares (arg) do -- en la función se accede a ellos como una tabla "arg" s = s + n end devuelve a end sum(1, 2, 3) -- devolverá 6 sum(1, 2, 3, 4) -- devolverá 10

Dado que las funciones son un tipo de datos completo, puede crear variables de función o puede pasar funciones como argumentos a otras funciones.

A = función(x) devuelve x * 2 fin -- función que multiplica por 2 b = función(x) devuelve x + 1 fin -- función que incrementa en 1 función aplicar(tabla, f) resultado = () para k, v in pairs(table) do result[k] = f(v) -- reemplaza el elemento con alguna función de este elemento end end -- PIENSA: lo que llama t = (1, 3, 5) apply(t, a) aplicar (t, b)

Objetos = funciones + tablas

Como podemos almacenar funciones en variables, también podemos almacenarlas en campos de tablas. Y ya resulta como si los métodos. Para aquellos que no están familiarizados con OOP, diré que su principal beneficio (al menos en Lua) es que las funciones y los datos con los que trabajan están cerca, dentro del mismo objeto. Para aquellos que están familiarizados con OOP, diré que aquí no hay clases y herencia de prototipos.

Pasemos a los ejemplos. Tenemos un objeto, digamos una bombilla. Sabe quemar y no quemar. Bueno, hay dos acciones que puedes hacer con él: encenderlo y apagarlo:

Lamp = ( on = false ) function turn_on(l) l.on = true end function turn_off(l) l.on = false end -- estas son solo funciones para trabajar con la estructura turn_on(lamp) turn_off(lamp)

Y si la bombilla se convierte en un objeto, y las funciones turn_off y turn_on se convierten en campos del objeto, entonces obtenemos:

Lámpara = ( encendido = falso encender_encender = función(l) l.encender = fin verdadero apagar_apagar = función(l) l.encender = fin falso ) lámpara.encender(lámpara) lámpara.apagar(lámpara)

Nos vemos obligados a pasar el objeto de la bombilla como primer argumento, porque de lo contrario nuestra función no sabrá con qué bombilla trabajar para cambiar el estado de encendido/apagado. Pero para no ser detallado, Lua tiene una abreviatura que generalmente se usa: lamp: turn_on (). En total, ya conocemos varias de estas simplificaciones de sintaxis:

lamp:turn_on() -- la notación más común lamp.turn_on(lamp) -- esto también es correcto desde el punto de vista de la sintaxis lamp["turn_on"](lamp) -- y esto

Continuando con las abreviaturas, las funciones pueden describirse no solo explícitamente, como campos de una estructura, sino también de una forma más conveniente:

Lamp = ( on = false ) -- a través de un punto, luego el argumento debe especificarse function lamp.turn_on(l) l.on = true end -- a través de dos puntos, luego el argumento se establece implícitamente, como la variable "self " -- "self" - y ahí está la bombilla para la cual se llamó el método de función lamp:turn_off() self.on = false end

¿Interesante?

Características especiales

Algunos nombres de funciones de tabla (métodos) están reservados y tienen un significado especial:

* __add(a, b), __sub(a, b), __div(a, b), __mul(a, b), __mod(a, b), __pow(a, b) - se llaman cuando se realizan operaciones aritméticas en la mesa
* __unm(a) - operación unaria "menos" (cuando escriben algo como "x = -x")
* __lt(a, b), __le(a, b), __eq(a, b) - calcular el resultado de la comparación (<, <=, ==)
* __len(a) - se llama cuando se hace "#a"
* __concat(a, b) - llamó a "a..b"
* __call(a, …) — llamada en "a()". Los argumentos variables son argumentos cuando se les llama
* __index(a, i) - acceso a a[i], siempre que dicho elemento no exista
* __nuevoíndice(a, i, v) - crea "a[i] = v"
* __gc(a) - cuando un objeto es eliminado por la recolección de basura

Al anular estos métodos, puede sobrecargar los operadores y utilizar la sintaxis del lenguaje para sus propios fines. Lo principal es no exagerar.

Herencia

Para aquellos que no conocen la programación orientada a objetos, la herencia le permite ampliar la funcionalidad de una clase ya existente. Por ejemplo, solo una bombilla puede encenderse y apagarse, y una bombilla superligera también cambiará su brillo. ¿Por qué necesitamos reescribir los métodos turn_on/turn_off cuando podemos reutilizarlos?

En Lua, existe un concepto de meta-tabla para esto, es decir tabla de antepasados. Cada tabla tiene una tabla principal y la tabla secundaria puede hacer todo lo que la principal puede hacer.

Digamos que ya hemos creado el objeto mesa lámpara. Entonces la súper bombilla se verá así:

Superlamp = (brillo = 100) -- especifique la tabla principal setmetatable(superlamp, lamp) -- y sus métodos ahora están disponibles superlamp:turn_on() superlamp:turn_off()

Extensión de funcionalidad

Muchos tipos tienen tablas principales (bueno, cadenas y tablas, números y valores booleanos, y nil no los tiene). Digamos que queremos agregar todas las cadenas usando el operador "+", no ".." . Para hacer esto, debe reemplazar la función "+" (__add) para la tabla principal de todas las filas:

S = getmetatable("") -- obtiene la tabla principal de la fila s.__add = function(s1, s2) return s1..s2 end -- cambia el método -- marca a = "hola" b = "mundo" imprimir(a + b) -- escribir "holamundo"

En realidad, todavía podemos reemplazar la función de impresión con "print = myfunction", y se pueden hacer muchas otras cosas.

Ámbitos

Las variables son globales o locales. Cuando se crean, todas las variables en Lua son globales.

PIENSA: ¿Por qué?

Para especificar el alcance local, escriba la palabra clave local:

Local x local var1, var2 = 5, 3

No olvides esta palabra.

Procesamiento de errores

A menudo, si se producen errores, es necesario detener la ejecución de una determinada función. Por supuesto, puede hacer muchas comprobaciones y llamar a "devolver" si algo salió mal. Pero esto aumentará la cantidad de código. Lua usa algo así como excepciones.

Los errores se generan utilizando la función error(x). Se puede pasar cualquier cosa como argumento (lo que está relacionado con el error: una descripción de cadena, un código numérico, un objeto con el que ocurrió un error, etc.)

Por lo general, después de esta función, todo el programa falla. Y esto no siempre es necesario. Si está llamando a una función que podría arrojar un error (o sus funciones secundarias podrían arrojar un error), llámela de manera segura con pcall():

Función f(x, y)... si... entonces error("no se pudo hacer algo") fin... estado final, err = pcall(f, x, y) -- f: función, xy: es argumentos si no es el estado entonces -- maneja el error err. En nuestro caso, err contiene el texto de error end

Bibliotecas estándar

Hay muchas bibliotecas no estándar, se pueden encontrar en LuaForge, LuaRocks y otros repositorios.

Entre Lua y no-Lua

Pero, ¿y si la funcionalidad de las bibliotecas estándar no es suficiente para nosotros? ¿Y si tenemos nuestro programa en C y queremos llamar a sus funciones desde Lua? Hay un mecanismo muy simple para esto.

Digamos que queremos crear nuestra propia función que devuelva un número aleatorio (Lua tiene math.random(), pero queremos aprender). Tendremos que escribir el siguiente código en C:

#incluir #incluir #incluir /* realmente qué hacer al llamar a `rand(from, to)` */ static int librand_rand(lua_State *L) ( int from, to; int x; from = lua_tonumber(L, 1); /* primer parámetro de función * / to = lua_tonumber(L, 2); /* segundo parámetro de función */ x = rand() % (to - from + 1) + from; lua_pushnumber(L, x); /* valor de retorno */ return 1; / * devuelve solo un argumento */ ) /* en Lua "rand" corresponde a nuestra función librand_rand() */ static const luaL_reg R = ( ("rand", librand_rand), (NULL, NULL) /* fin de la lista de exportados funciones */); /* se llama cuando se carga la biblioteca */ LUALIB_API int luaopen_librand(lua_State *L) ( luaL_openlib(L, "librand", R, 0); srand(time(NULL)); return 1; /* exito */ )

Esos. Lua nos proporciona funciones para trabajar con tipos de datos, para tomar argumentos de función y devolver resultados. Hay muy pocas funciones, y son bastante simples. Ahora construimos nuestra biblioteca como dinámica y podemos usar la función rand():

Random = require("librand") -- carga la biblioteca print(random.rand(1, 100)) print(random.rand(0, 1))

¿Qué pasa si queremos llamar al código Lua desde nuestros programas? Luego, nuestros programas deberían crear una máquina virtual Lua, en la que se ejecutarán los scripts Lua. Es mucho más fácil:

#include "lua.h" #include "lauxlib.h" int main() ( lua_State *L = lua_open(); // crea la máquina virtual Lua luaL_openlibs(L); // carga las bibliotecas estándar luaL_dofile(L, " rand. lua"); // ejecuta el script lua_close(L); // cierra Lua return 0; )

Todo.

Ahora puedes escribir en Lua. Si encuentra puntos interesantes sobre Lua que podrían reflejarse en el artículo, ¡escriba!

En esta serie de tutoriales que concebí, se discutirá el lenguaje de programación Lua. Intentaré que la presentación sea lo más accesible posible para los principiantes y me centraré en ellos. Es decir, los codificadores de Lua experimentados, muy probablemente, no aprenderán nada nuevo aquí (estoy seguro de que solo encontrarán espacio para quisquillosos y comentarios aquí, que, de hecho, incluso son bienvenidos de su parte), pero si no tienes una rica experiencia en programación detrás de ti, entonces creo que obtendrás algo.

Toda la serie no obedecerá a ningún sistema. Las lecciones presentarán secuencialmente una serie de construcciones de lenguaje para que en la tercera o cuarta lección ya pueda escribir sus programas. Mi objetivo es empujarte a estudiar el idioma por tu cuenta, ayudarte a sentirlo, no explicarlo de la A a la Z. Si quieres dominar el idioma por completo, lee la guía de referencia (que, aunque mal, está traducida al ruso: http://www.lua .ru/doc/). Cuanto antes pase de los tutoriales "para tontos" en la Web al manual, mejor.

Si algo no está claro, asegúrese de hacer una pregunta en los comentarios, y yo y otros participantes intentaremos ayudarlo.

Lua es un lenguaje de programación popular, fácil de aprender, de uso general, integrable, interpretado y tipificado dinámicamente. No, no necesita comprender ni la mitad de las palabras de la oración anterior; lo principal es saber que es popular y sin complicaciones. Por cierto, la sencillez, así como el pequeño tamaño de la distribución (alrededor de 150 kilobytes), le hicieron merecedora de su popularidad. Las secuencias de comandos de Lua son compatibles con una amplia gama de aplicaciones, incluidos los juegos. World of Warcraft y S.T.A.L.K.E.R. usa el idioma Lua. Mi motor de juego favorito te permite crear fácilmente una variedad de juegos con Lua. Como puedes ver, ¡Lúa te abre muchos horizontes!

Antes de comenzar, debe configurar un entorno de programación: es decir, encontrar un programa que tome el código Lua que escribe y lo ejecute: un intérprete. Hay tres opciones aquí:

1. Descarga la distribución oficial de Lua desde uno de los sitios que la suministran.

Desde el sitio web oficial de Lua, puede descargar solo los códigos fuente del intérprete. Sin embargo, si busca en http://lua.org/download.html en la sección Binarios, puede encontrar enlaces a sitios con ejecutables de Windows. Uno de ellos: . Descargue uno de los archivos desde allí (que coincida con su plataforma: Win32 o Win64) y extráigalo en algún lugar, preferiblemente en un directorio con una ruta corta: como C:\lua. De ahora en adelante, asumiré que está utilizando Windows y que su intérprete se encuentra allí.

Los usuarios de sistemas operativos basados ​​en Linux son más fáciles en este sentido: solo necesitan usar el administrador de paquetes e instalar Lua desde los repositorios. En Debian y Ubuntu, esto se hace con apt-get install lua, y en Fedora, Red Hat y derivados, yum install lua. Sin embargo, no confíes en mí a ciegas y consulta el manual de tu sistema operativo para saber exactamente cómo funciona para ti.

2. Utilice un intérprete en línea.

Ubicado en http://www.lua.org/demo.html. Al principio puede ser suficiente, pero en el futuro, cuando toquemos los módulos, te verás obligado a usar la versión sin conexión. Usar el intérprete en línea es muy simple: ingrese su programa en el cuadro de texto y haga clic en el botón Ejecutar. El programa se ejecutará, la salida de su programa aparecerá en la ventana Salida, así como los informes de error, si los hubiere, por su parte.

3. Utilice un IDE.

Por ejemplo, ZeroBrane Studio: http://studio.zerobrane.com/ . Hay otros, busque en línea.

Actualmente se utilizan dos versiones ligeramente diferentes de Lua: 5.1 y 5.2. Me centraré en la versión más reciente, la versión 5.2, pero asegúrese de señalar diferencias importantes entre esta y la 5.1, ya que esta última también es bastante común. Por cierto, Lua 5.1 ejecuta el código una vez y media más rápido que Lua 5.2, para que lo sepas.

=== Lección #1 ===

Vamos a empezar. Cree un archivo main.lua en una carpeta aislada de archivos externos y escríbalo:

200?"200px":""+(this.scrollHeight+5)+"px");">
-- principal.lua --
imprimir("¡Hola mundo!")

Luego ejecute en la línea de comando (no olvide moverse al directorio con main.lua usando el comando cd):

200?"200px":""+(this.scrollHeight+5)+"px");">
> C:\lua\lua.exe principal.lua

En respuesta, el intérprete de Lua emitirá:

200?"200px":""+(this.scrollHeight+5)+"px");">
¡Hola Mundo!

Básicamente, esto es de esperar. En el programa, llamamos a la función de impresión. La función de impresión toma un número arbitrario de parámetros y los imprime secuencialmente en la pantalla. En este ejemplo, le pasamos la cadena (cadena de caracteres) "¡Hola mundo!". Con el mismo éxito, puedes pasar como parámetro:

200?"200px":""+(this.scrollHeight+5)+"px");">
print(8) -- algún número decimal
-- salida: 8

Imprimir (0xDEADBEEF) -- número hexadecimal
-- salida: 3735928559

Print("0xDEADBEEF") -- ¡y esto es una cadena, no un número! ¿Ves las citas?
-- imprime: 0xDEADBEEF

Imprimir (1.35e-4) -- número de punto flotante (fraccional)
-- Salidas 0.000135. 1.35e-4 debe entenderse como "1.35 veces
- por diez a la menos cuarta potencia", si alguien no lo sabe.

Imprimir ((198*99)-3*500 + 14/88) -- expresión
-- Muestra el valor de la expresión: 18102.159090909. No es mala alternativa
-- una calculadora de escritorio!

Imprimir (198/7, "fertilizante", 2 ^ 9) - algunos parámetros de arbitraria
-- escribe. Se mostrarán los valores de cada uno de ellos, separados por signos.
-- pestañas:
-- 28.285714285714 abono 512
-- ¡Tenga en cuenta que las cotizaciones sobre fertilizantes no se imprimen!

Imprimir (1.35) -- ¡dos números, no decimal 1.35!
-- Se usa una coma para separar las opciones.
-- Salidas:
-- 1 35

El signo "--" no es solo una imitación de un guión, que se inserta por belleza. El signo "--" en Lua marca los comentarios: sugerencias para el programador que el intérprete ignora y cuyo objetivo es facilitar la comprensión del código. Puedes intentar escribir en el programa:

200?"200px":""+(this.scrollHeight+5)+"px");">
--imprimir("nada")

El intérprete pensará que es un comentario y no ejecutará la instrucción.

Nota para la anfitriona: si desea imprimir solo una línea, puede escribir la llamada de impresión así, sin paréntesis:

200?"200px":""+(this.scrollHeight+5)+"px");">
imprimir "Solo una cadena"

La conveniencia es ciertamente cuestionable: solo tenga en cuenta que esto es posible. Sin embargo, tales llamadas no están permitidas:

200?"200px":""+(this.scrollHeight+5)+"px");">
print 2 no funcionará, 2 no es una cadena.
imprime 2*2 + 6 -- tanto más no funcionará

Str = "cadena!!" -- establezca la variable str en "cadena!!"
-- lea sobre las variables a continuación
print str -- tampoco funcionará.

En cada uno de los casos anteriores, el programa simplemente se negará a funcionar. Por lo tanto, en una llamada "sin paréntesis", solo un literal de cadena (es decir, una secuencia de caracteres entre comillas) puede seguir al nombre de la función, y nada más. En el futuro, hablaré sobre esta función con un poco más de detalle, pero por ahora, eso es suficiente para ti.

En cualquier buen lenguaje de programación, es posible declarar variables: pequeños contenedores que pueden contener algún tipo de datos. En Lua esto se hace así:

200?"200px":""+(this.scrollHeight+5)+"px");">
<имя_переменной> = <выражение>

Por ejemplo:

200?"200px":""+(this.scrollHeight+5)+"px");">
estrella = 8 -- La variable estrella ahora almacena el número 8
wars = "owl" -- En la variable wars, la cadena "owl"
jedi = 42/2 -- La variable jedi es el número 21
luke = star*jedi -- La variable luke es el número 168 (sí, 21 veces 8)

Los valores de las variables y expresiones con ellos también se pueden mostrar en la pantalla:

200?"200px":""+(this.scrollHeight+5)+"px");">
imprimir (estrella, guerras, jedi, jedi-star + luke)
-- Salidas:
-- 8 lechuzas 21 181

Simplemente no intente agregar las variables star y wars: ¡intentar agregar 8 a "owl" no le servirá de nada!

Como habrás notado, el nombre de una variable puede ser casi cualquier cosa: lo principal es que no comience con un número. En serio, incluso puede declarar una variable llamada imprimir y luego la función de impresión dejará de funcionar porque el nombre imprimir se referirá a la variable recién declarada. Pero hay un grupo de palabras que está prohibido usar como nombres de variables: estas son palabras clave de idioma que aún no conocemos, pero que definitivamente vale la pena ver:

200?"200px":""+(this.scrollHeight+5)+"px");">
y romper hacer otra cosa si terminar
falso para la función ir a si en
local nulo no o repetir retorno
entonces cierto hasta mientras

Al crear una variable con uno de estos nombres, provocará un error en el programa y definitivamente no funcionará. Tenga en cuenta que en Lua 5.1 no hay una palabra clave goto, y puede llamar a una variable, pero es mejor que no lo haga.
También tenga en cuenta que los nombres de las variables distinguen entre mayúsculas y minúsculas. Esto significa que foo, fOo, fOO y FOO son cuatro variables diferentes, por lo que si escribes el nombre de una variable en minúsculas y luego lo escribes en mayúsculas, lo más probable es que el programa no funcione correctamente.

Y ahora un punto importante: ¿qué pasa si, accidental o intencionadamente, haces referencia a una variable inexistente? En la mayoría de los demás idiomas, esto generará un error, pero en Lua esta situación es aceptable. Se trata como si una variable inexistente realmente existiera, pero su valor es nulo. nulo- ¡Recuerda esta palabra! es un tipo especial de valor en Lua que significa "nada". Ni cero ni una cadena vacía (una cadena como "" - intente mostrarla en la pantalla), sino simplemente nada. Compare esto con este modelo: hay dos personas, una de ellas tiene una cuenta bancaria, pero no tiene dinero, y la otra no tiene ninguna cuenta bancaria. En términos de Lua, se considerará que la cuenta del primero tiene 0 dólares, y la cuenta del segundo tiene nulo. Y ni siquiera dólares, sino simplemente nulo. Espero no haberte confundido.

Intente, por ejemplo, ejecutar el siguiente programa:

200?"200px":""+(this.scrollHeight+5)+"px");">
-- principal.lua --
foo="barra"
imprimir (foo, baz)
-- Salidas:
-- barra cero

Por lo tanto, la variable baz, que no existe pero se supone que existe, tiene el valor nil, y la función de impresión lo entiende y lo imprime en la pantalla como la cadena "nil". Lua tiene un buen método para comprobar la existencia de una variable: si el valor de una variable no es nulo, al menos se declara. Por otro lado, puedes declarar explícitamente una variable igual a cero:

200?"200px":""+(this.scrollHeight+5)+"px");">
cool_var = cero

Esto se puede hacer, y aunque parezca una tontería a primera vista, a veces se hace. En lecciones posteriores, aprenderá quién y por qué, y probablemente comenzará a hacer lo mismo. A veces, por supuesto.
Tenga cuidado con nil ": puede imprimir nil, ¡pero no puede hacer aritmética con él! Es decir, si print (nil) se sale con la suya, entonces una construcción como 99 + nil causará un error, incluso si lo hiciera como 99+ cero era 99. Créeme, también me molesté cuando me enteré.

Resumen:
1. Aprendimos sobre la función de impresión, qué puede hacer y cómo llamarla correctamente sin paréntesis.
2. Aprendimos cómo declarar variables, cómo evaluar expresiones (aunque bastante), qué nombres pueden tener las variables.
3. Aprendimos sobre el cero, nos imbuimos de su misterio místico y ganamos confianza en que en el futuro estaremos conectados con él.

Para aquellos que son curiosos y quieren fortalecer sus conocimientos, ofrezco ejercicios simples, que puede omitirse si ya se siente lo suficientemente competente:
1. Escriba un programa que imprima el coro de su canción favorita.
2. Intenta mostrar los valores de las siguientes expresiones. Trate de entender por qué algunos de ellos funcionan y otros no. Vea qué errores son causados ​​por expresiones rotas.

200?"200px":""+(this.scrollHeight+5)+"px");">
2 + "cadena";
6 + "14";
"caja" - "voz";
1 * "11b"
"148" * "1e6";


3. Escriba un programa que intercambie dos variables. Es decir:

200?"200px":""+(this.scrollHeight+5)+"px");">
a = 6502
b=8086


Haz a igual a 8086 yb igual a 6502. Para hacer esto, crea una tercera variable y haz permutaciones simples. Asegúrese de que el problema se resuelva correctamente llamando a print(a,b) antes del intercambio y print(a,b) después.

¿Te gustó el artículo? Compártelo