Sé lo que my
hay en Perl. Define una variable que existe solo en el ámbito del bloque en el que se define. ¿Qué our
hacer?
¿Cómo our
difiere de my
?
Sé lo que my
hay en Perl. Define una variable que existe solo en el ámbito del bloque en el que se define. ¿Qué our
hacer?
¿Cómo our
difiere de my
?
Respuestas:
Gran pregunta: ¿en qué se our
diferencia my
y qué hace our
?
En resumen:
Disponible desde Perl 5, my
es una forma de declarar variables que no son paquetes, que son:
$package_name::variable
.Por otro lado, las our
variables son variables de paquete y, por lo tanto, automáticamente:
$package_name::variable
.Declarar una variable con le our
permite predefinir variables para usarlas use strict
sin recibir advertencias tipográficas o errores en tiempo de compilación. Desde Perl 5.6, ha reemplazado el obsoleto use vars
, que solo tenía un alcance de archivo y no tenía un alcance léxico tal como está our
.
Por ejemplo, el nombre formal y calificado para la variable $x
dentro package main
es $main::x
. La declaración le our $x
permite usar la $x
variable básica sin penalización (es decir, sin un error resultante), en el alcance de la declaración, cuando el script usa use strict
o use strict "vars"
. El alcance puede ser uno, o dos, o más paquetes, o un bloque pequeño.
local
no crea variables. No se relaciona con my
y our
en absoluto. local
respalda temporalmente el valor de la variable y borra su valor actual.
our
Las variables no son variables de paquete. No son de ámbito global, sino variables de ámbito léxico al igual que las my
variables. Se puede ver que en el siguiente programa: package Foo; our $x = 123; package Bar; say $x;
. Si desea "declarar" una variable de paquete, debe usarla use vars qw( $x );
. our $x;
declara una variable de ámbito léxico con alias a la variable del mismo nombre en el paquete en el que our
se compiló.
Los enlaces PerlMonks y PerlDoc de cartman y Olafur son una gran referencia: a continuación se muestra mi resumen:
my
las variables tienen un ámbito léxico dentro de un solo bloque definido por {}
o dentro del mismo archivo si no está en {}
s. No son accesibles desde paquetes / subrutinas definidas fuera del mismo ámbito / bloque léxico.
our
las variables se definen dentro de un paquete / archivo y son accesibles desde cualquier código que use
o require
ese paquete / archivo: los conflictos de nombre se resuelven entre paquetes anteponiendo el espacio de nombres apropiado.
Solo para redondearlo, las local
variables tienen un alcance "dinámico", que difiere de las my
variables en que también son accesibles desde subrutinas llamadas dentro del mismo bloque.
my
variables tienen un alcance [...] léxico dentro del mismo archivo si no están en {}
s". Eso fue útil para mí, gracias.
Un ejemplo:
use strict;
for (1 .. 2){
# Both variables are lexically scoped to the block.
our ($o); # Belongs to 'main' package.
my ($m); # Does not belong to a package.
# The variables differ with respect to newness.
$o ++;
$m ++;
print __PACKAGE__, " >> o=$o m=$m\n"; # $m is always 1.
# The package has changed, but we still have direct,
# unqualified access to both variables, because the
# lexical scope has not changed.
package Fubb;
print __PACKAGE__, " >> o=$o m=$m\n";
}
# The our() and my() variables differ with respect to privacy.
# We can still access the variable declared with our(), provided
# that we fully qualify its name, but the variable declared
# with my() is unavailable.
print __PACKAGE__, " >> main::o=$main::o\n"; # 2
print __PACKAGE__, " >> main::m=$main::m\n"; # Undefined.
# Attempts to access the variables directly won't compile.
# print __PACKAGE__, " >> o=$o\n";
# print __PACKAGE__, " >> m=$m\n";
# Variables declared with use vars() are like those declared
# with our(): belong to a package; not private; and not new.
# However, their scoping is package-based rather than lexical.
for (1 .. 9){
use vars qw($uv);
$uv ++;
}
# Even though we are outside the lexical scope where the
# use vars() variable was declared, we have direct access
# because the package has not changed.
print __PACKAGE__, " >> uv=$uv\n";
# And we can access it from another package.
package Bubb;
print __PACKAGE__, " >> main::uv=$main::uv\n";
Hacer frente a Scoping es una buena descripción de las reglas de alcance de Perl. Es lo suficientemente viejo que our
no se discute en el cuerpo del texto. Se trata en las Notas sección de al final.
El artículo habla sobre las variables del paquete y el alcance dinámico y cómo difiere de las variables léxicas y el alcance léxico.
my
se usa para variables locales, mientras que our
se usa para variables globales.
Más lectura en Variable Scoping en Perl: lo básico .
${^Potato}
es global Se refiere a la misma variable independientemente de dónde la use.
Alguna vez encontré algunas trampas sobre declaraciones léxicas en Perl que me confundieron, que también están relacionadas con esta pregunta, así que solo agrego mi resumen aquí:
1. Definición o declaración?
local $var = 42;
print "var: $var\n";
La salida es var: 42
. Sin embargo, no podríamos decir si local $var = 42;
es una definición o declaración. Pero qué tal esto:
use strict;
use warnings;
local $var = 42;
print "var: $var\n";
El segundo programa arrojará un error:
Global symbol "$var" requires explicit package name.
$var
no está definido, lo que significa que local $var;
es solo una declaración! Antes de usar local
para declarar una variable, asegúrese de que esté definida como una variable global previamente.
¿Pero por qué esto no fallará?
use strict;
use warnings;
local $a = 42;
print "var: $a\n";
La salida es: var: 42
.
Eso es porque $a
, además de $b
, es una variable global predefinida en Perl. ¿Recuerdas la función de clasificación ?
2. ¿Léxico o global?
Era un programador en C antes de comenzar a usar Perl, por lo que el concepto de variables léxicas y globales me parece sencillo: solo corresponde a las variables automáticas y externas en C. Pero hay pequeñas diferencias:
En C, una variable externa es una variable definida fuera de cualquier bloque de funciones. Por otro lado, una variable automática es una variable definida dentro de un bloque de funciones. Me gusta esto:
int global;
int main(void) {
int local;
}
Mientras que en Perl, las cosas son sutiles:
sub main {
$var = 42;
}
&main;
print "var: $var\n";
La salida es var: 42
. $var
es una variable global incluso si está definida en un bloque de funciones! En realidad, en Perl, cualquier variable se declara como global de forma predeterminada.
La lección es agregar siempre use strict; use warnings;
al comienzo de un programa Perl, lo que obligará al programador a declarar explícitamente la variable léxica, para que no nos equivoquemos por algunos errores que se dan por sentados.
El perldoc tiene una buena definición de nuestro.
A diferencia de my, que asigna almacenamiento para una variable y asocia un nombre simple con ese almacenamiento para usar dentro del alcance actual, nuestro asocia un nombre simple con una variable de paquete en el paquete actual, para usar dentro del alcance actual. En otras palabras, nuestro tiene las mismas reglas de alcance que mi, pero no necesariamente crea una variable.
Esto solo está algo relacionado con la pregunta, pero acabo de descubrir un poco (para mí) oscuro sintaxis de Perl que puedes usar con "nuestro" (paquete) variables que no puedes usar con "mi" (local) variables
#!/usr/bin/perl
our $foo = "BAR";
print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";
Salida:
BAR
BAZ
Esto no funcionará si cambia 'nuestro' a 'mi'.
perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"
salida: barbaz
perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"
salida: barbaz
perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
salida: barbar
así que en mis pruebas caí en la misma trampa. $ {foo} es lo mismo que $ foo, los corchetes son útiles al interpolar. $ {"foo"} es en realidad una búsqueda de $ main :: {} que es la tabla de símbolos principal, ya que solo contiene variables de ámbito de paquete.
perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
trabajo sensible al paquete , ya que en este contexto $ {"foo"} ahora es igual a $ {"test :: foo"}. Of Symbol Tables and Globs tiene algo de información, al igual que el libro de programación Advanced Perl. Perdón por mi error anterior.
print "package is: " . __PACKAGE__ . "\n";
our $test = 1;
print "trying to print global var from main package: $test\n";
package Changed;
{
my $test = 10;
my $test1 = 11;
print "trying to print local vars from a closed block: $test, $test1\n";
}
&Check_global;
sub Check_global {
print "trying to print global var from a function: $test\n";
}
print "package is: " . __PACKAGE__ . "\n";
print "trying to print global var outside the func and from \"Changed\" package: $test\n";
print "trying to print local var outside the block $test1\n";
Producirá esto:
package is: main
trying to print global var from main package: 1
trying to print local vars from a closed block: 10, 11
trying to print global var from a function: 1
package is: Changed
trying to print global var outside the func and from "Changed" package: 1
trying to print local var outside the block
En caso de usar "use estricto" obtendrá este error al intentar ejecutar el script:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
Solo intenta usar el siguiente programa:
#!/usr/local/bin/perl
use feature ':5.10';
#use warnings;
package a;
{
my $b = 100;
our $a = 10;
print "$a \n";
print "$b \n";
}
package b;
#my $b = 200;
#our $a = 20 ;
print "in package b value of my b $a::b \n";
print "in package b value of our a $a::a \n";
#!/usr/bin/perl -l
use strict;
# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'
our $lol = eval {$lol} || 'lol' ;
print $lol;
our
y my
diferentes? ¿Cómo lo muestra este ejemplo?
Pensemos qué es realmente un intérprete: es un código que almacena valores en la memoria y permite que las instrucciones en un programa que interpreta accedan a esos valores por sus nombres, que se especifican dentro de estas instrucciones. Entonces, el gran trabajo de un intérprete es dar forma a las reglas de cómo debemos usar los nombres en esas instrucciones para acceder a los valores que almacena el intérprete.
Al encontrar "my", el intérprete crea una variable léxica: un valor con nombre al que el intérprete puede acceder solo mientras ejecuta un bloque, y solo desde ese bloque sintáctico. Al encontrar "nuestro", el intérprete crea un alias léxico de una variable de paquete: vincula un nombre, que el intérprete debe procesar a partir de ese momento como el nombre de una variable léxica, hasta que el bloque haya finalizado, con el valor del paquete variable con el mismo nombre.
El efecto es que puede pretender que está utilizando una variable léxica y omitir las reglas de 'uso estricto' en la calificación completa de las variables del paquete. Como el intérprete crea automáticamente las variables del paquete cuando se usan por primera vez, el efecto secundario del uso de "nuestro" también puede ser que el intérprete cree también una variable del paquete. En este caso, se crean dos cosas: una variable de paquete, a la que el intérprete puede acceder desde cualquier lugar, siempre que esté debidamente designada como solicitada por 'use estricto' (antepuesto con el nombre de su paquete y dos puntos), y su alias léxico.
Fuentes: