Structs
Agregados en vJASS, los structs (cuando son correctamente utilizados) nos facilitan mucho la vida. No hay nada que no podamos hacer sin ellos (es opcional aprenderlos) pero si nos ayudan a organizar y a hacer mas legible nuestro código (esto es MUY importante).
Los structs nos permiten pensar en objetos. Pensemos por un momento, en una persona. Sabemos que esa persona tiene un nombre, una edad, color de cabello y demás atributos que lo definen. Además sabemos que puede realizar ciertas acciones, como caminar, hablar, y demás tipo de funciones.
¿Cómo pasaríamos esto a un struct?
Primero que nada, debemos definir nuestro struct Persona:
[jass]struct Persona
endstruct[/jass]
Dijimos que la persona tenía atributos como su nombre, edad, etc.
[jass]struct Persona
string nombre
integer edad
endstruct[/jass]
Y por último mencionamos que poseía ciertas acciones (caminar, hablar, y demás):
[jass]struct Persona
string nombre
integer edad
method caminar takes nothing returns nothing
endmethod
method hablar takes nothing returns nothing
endmethod
endstruct[/jass]
Nota: [ljass]method[/ljass] es "lo mismo" que decir [ljass]function[/ljass].
Ahora bien, tenemos el "molde" de una persona, vamos a crear (instanciar) una en si:
[ljass]Persona franco = Persona.create()[/ljass]
Ya tenemos a una persona. Nótese cómo en lugar de poner [ljass]integer[/ljass], [ljass]string[/ljass], [ljass]real[/ljass] o cualquier otro tipo de variable, colocamos Persona.
Ahora que tenemos nuestra persona, vamos a darle un nombre y edad:
[jass]set franco.nombre = "Franco"
set franco.edad = 19[/jass]
Ahora digamos que quiero crear otra persona:
[jass]Persona maria = Persona.create()
set maria.nombre = "Maria"
set maria.edad = 21[/jass]
Ya jugamos con los atributos, vimos cómo asignarles valor. Ahora vamos a ver cómo llamar a sus funciones/acciones.
Anteriormente, habíamos creado dos métodos, los cuales eran caminar y hablar, pero ninguno de ellos hacía nada, así que vamos a modificar eso:
[jass]struct Persona
string nombre
integer edad
method caminar takes nothing returns nothing
call BJDebugMsg("está caminando")
endmethod
method hablar takes nothing returns nothing
call BJDebugMsg("está hablando")
endmethod
endstruct[/jass]
Ahora vamos a hacer que la persona "franco" camine, y que la persona "maria" hable:
[jass]Persona franco = Persona.create()
Persona maria = Persona.create()
set franco.nombre = "Franco"
set franco.edad = 19
@franco.caminar()@
set maria.nombre = "Maria"
set maria.edad = ?
@maria.hablar()@[/jass]
Si probamos esto, simplemente salen dos mensajes ("está caminando" y "está hablando"). Pero esto es aburrido, ¿no sería bueno que diga además, quién está caminando o quién está hablando?. Vamos a modificarlo para que tenga ese comportamiento:
[jass]struct Persona
string nombre
integer edad
method caminar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está caminando")
endmethod
method hablar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está hablando")
endmethod
endstruct[/jass]
Probamos, y efectivamente obtenemos: "Franco está caminando" y "Maria está hablando". Funciona tal y como lo habíamos planeado, pero qué es [ljass]this[/ljass].
[ljass]this[/ljass] toma el valor de la instancia con la que estamos trabajando. Recordar que cada persona, es una instancia de Persona (valga la redundancia). Esto se podría traducir en lo siguiente:
Franco[jass] method caminar takes nothing returns nothing
call BJDebugMsg(@franco@.nombre + " está caminando")
endmethod[/jass]
Maria[jass]method hablar takes nothing returns nothing
call BJDebugMsg(@maria@.nombre + " está hablando")
endmethod[/jass]
En los ejemplos anteriores, vimos cómo modificar y obtener atributos... pero hay un problema, ¿acaso podemos modificar el nombre o la edad de una persona a voluntad?, por supuesto que no.
Muchas veces, nos encontraremos (o se encontrarán) con estos problemas, en los que no queremos que un valor pueda modificarse y obtenerse, o que no se pueda modificar pero si obtener o viceversa. Estas situaciones, se resuelven determinando la visibilidad.
Volviendo al struct Persona. Queremos que el atributo nombre solamente pueda asignarse una vez, lo mismo para el atributo edad. Para ello, vamos a tener que hacer varios cambios:
[jass]struct Persona
@readonly@ string nombre
@readonly@ integer edad
method caminar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está caminando")
endmethod
method hablar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está hablando")
endmethod
static method create takes string nombre, integer edad returns Persona
local Persona this = Persona.allocate()
set this.nombre = nombre
set this.edad = edad
return this
endmethod
endstruct[/jass]
[ljass]readonly[/ljass]: Se podría traducir a "solo leer". Esto quiere decir que si intentamos darle valor (como lo hicimos anteriormente) tendremos un error. Solo la podemos "leer"
[ljass]static method create[/ljass]: ¿Recuerdas que para instanciar (crear) una nueva persona, teníamos que hacer [ljass]Persona.create()[/ljass]?, como ahora hemos cambiado las cosas, para instanciar una nueva persona, debemos hacer [ljass]Persona.create(<nombre>, <edad>)[/ljass].
[ljass]local Persona this = Persona.allocate()[/ljass]: En esta línea, decimos que necesitamos crear una nueva instancia, por lo que nos devuelve una lista para usar.
[ljass]return this[/ljass]: Ya tenemos nuestra instancia, trabajamos con ella (asignando valores) y decimos que ya está lista para que se use, por lo que la "devolvemos".
¿Has notado el [ljass]static[/ljass] en el método [ljass]create[/ljass]?
[ljass]static[/ljass] no trabaja con instancias, trabaja con el "struct en si". Como anteriormente vimos, cuando llamábamos a [ljass]create[/ljass], lo hacíamos con [ljass]@Persona@.create()[/ljass]. Mas adelante lo vamos a estar viendo un poco mas a fondo.
Volviendo a lo que queríamos hacer, dijimos que tanto nombre como edad solamente se podrían asignar (darle valor) una sola vez. Con esto, ya lo hemos logrado.
Ahora, ¿qué pasa cuando tenemos un atributo que no queremos que se pueda obtener ni modificar?, para estos casos, se hace uso de [ljass]private[/ljass].
Supongamos que cada persona, tiene la contraseña de su cuenta bancaria. Este es un valor el cual no queremos revelar a otras personas y tampoco podemos modificarlo.
[jass]struct Persona
readonly string nombre
readonly integer edad
@private string contraseña_bancaria@
method caminar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está caminando")
endmethod
method hablar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está hablando")
endmethod
static method create takes string nombre, integer edad, @string contraseña_bancaria@ returns Persona
local Persona this = Persona.allocate()
set this.nombre = nombre
set this.edad = edad
@set this.contraseña_bancaria = contraseña_bancaria@
return this
endmethod
endstruct[/jass]
Si intentamos algo como:
[jass]set franco.contraseña_bancaria = "1234"
call BJDebugMsg(franco.contraseña_bancaria)[/jass]
Veremos que nos arroja un error.
Nota: El uso de "ñ" no es válido, solo es para el ejemplo.
La visibilidad puede asignarse tanto a atributos como a métodos.
Dijimos que static no utilizaba instancias, si no que trabaja con "el struct en si". Tanto los atributos como métodos estáticos, no son útiles para cuando tenemos un caso en donde no es necesario instanciar (por ejemplo, el atributo nombre no podría ser estático, puesto que no todas las personas tienen el mismo nombre).
Por ejemplo, supongamos que queremos tener un conteo de todas las personas que han sido creadas. Para ello, podemos crear un atributo estático cuyo valor sea, precisamente, la cantidad de personas que han sido creadas. Además, queremos saberlo, pero hay un detalle, ¡no debemos ser capaces de modificar ese valor!.
[jass]struct Persona
@readonly static integer contador = 0@
readonly string nombre
readonly integer edad
private string contraseña_bancaria
static method mencionarCantidadDePersonas takes nothing returns nothing
call BJDebugMsg("En total hay " + I2S(Persona.contador) + " personas")
endmethod
method caminar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está caminando")
endmethod
method hablar takes nothing returns nothing
call BJDebugMsg(this.nombre + " está hablando")
endmethod
static method create takes string nombre, integer edad, string contraseña_bancaria returns Persona
local Persona this = Persona.allocate()
set this.nombre = nombre
set this.edad = edad
set this.contraseña_bancaria = contraseña_bancaria
@set Persona.contador = Persona.contador + 1@
return this
endmethod
endstruct[/jass]
Nótese que en el método [ljass]create[/ljass] estamos aumentando en uno (1) el contador de personas, esto es porque, ¡acabamos de crear una persona!.
Ahora que hemos agregado el contador, podemos llevar el registro de la cantidad de personas que han sido creadas, y además:
[ljass]Persona.mencionarCantidadDePersonas()[/ljass]
Podemos crear un mensaje mencionando la cantidad de personas
.
Si has llegado a esta parte de este breve tutorial, mis felicitaciones pues lo has completado
. Espero que se haya entendido y no haya sido muy complejo.
Ante cualquier duda, me comentan y solucionamos
.
Saludos.