20.3. Variables locales

Una variable local tiene un nombre que empieza con una letra minúscula o con el carácter de subrayado (_). Las variables locales no tienen, a diferencia de las variables globales y las variables de instancia, el valor nil antes de la inicialización:


ruby> $foo
nil
ruby> @foo
nil
ruby> foo
ERR: (eval):1: undefined local variable or method `foo' for #<Object:0x401d2c90>

La primera asignación que se realiza sobre una variable local actúa como una declaración. Si se referencia a una variable local no inicializada, el intérprete de Ruby piensa que se trata de una llamada a un método con ese nombre; de ahí el mensaje de error del ejemplo anterior.

Generalmente el ámbito de una variable local es uno de los siguientes:

En el siguiente ejemplo define? es un operador que verifica si un identificador está definido. Si lo está, devuelve una descripción del mismo, en caso contrario, devuelve nil. Como se ve el ámbito de bar es local al bucle, cuando se sale del bucle, bar está sin definir.


ruby> foo =44; print foo, "\n"; defined? foo
44
"local-variable"
ruby> loop{bar = 45;print bar, "\n"; break}; defined? var
45
nil

Los objetos procedimiento que residen en el mismo ámbito comparten las variables locales que pertenecen a ese ámbito. En el siguiente ejemplo, la variable bar es compartida por main y los objetos procedimiento p1 y p2:


ruby> bar=0
0
ruby> p1 = proc{|n| bar = n}
#<Proc:0x401c3e34>
ruby> p2 = proc{bar}
#<Proc:0x401c3cf4>
ruby> p1.call(5)
5
ruby> bar
5
ruby> p2.call
5

Obsérvese que no se puede omitir la línea bar=0 inicial; esta asignación es la que garantiza que el ámbito de bar incluirá a p1 y p2. Si no, p1 y p2 tendrán al final cada uno su propia variable local bar y la llamada a p2 dará lugar a un error de "variable o método no definido".

Una característica muy poderosa de los objetos procedimiento se deriva de su capacidad para recibir argumentos; las variables locales compartidas permanecen válidas incluso cuando se las pasa fuera de su ámbito original.


ruby> def box
ruby|   contents = 15
ruby|   get = proc{contents}
ruby|   set = proc{|n| contents = n}
ruby|   return get, set
ruby| end
nil
ruby> reader, writer = box
[#<Proc:0x401c33d0>, #<Proc:0x401c33bc>]
ruby> reader.call
15
ruby> writer.call(2)
2
ruby> reader.call
2

Ruby es especialmente inteligente con respecto al ámbito. En el ejemplo, es evidente que la variable contents está compartida por reader y writer. Ahora bien, es posible definir varios pares reader-writer que utilicen box cada uno de los cuales comparten su propia variable contents sin interferir uno con otro.


ruby> reader_1, writer_1 = box
[#<Proc:0x401c2e6c>, #<Proc:0x401c2e58>]
ruby> reader_2, writer_2 = box
[#<Proc:0x401c2cdc>, #<Proc:0x401c2cc8>]
ruby> writer_1.call(99)
99
ruby> reader_1.call
99
ruby> reader_2.call
15