¿Cuál es la diferencia entre 'my' y 'our' en Perl?

188

Sé lo que myhay en Perl. Define una variable que existe solo en el ámbito del bloque en el que se define. ¿Qué ourhacer?

¿Cómo ourdifiere de my?

Nathan Fellman
fuente

Respuestas:

215

Gran pregunta: ¿en qué se ourdiferencia myy qué hace our?

En resumen:

Disponible desde Perl 5, myes una forma de declarar variables que no son paquetes, que son:

  • privado
  • nuevo
  • no global
  • separado de cualquier paquete, de modo que no se pueda acceder a la variable en forma de $package_name::variable.


Por otro lado, las ourvariables son variables de paquete y, por lo tanto, automáticamente:

  • variables globales
  • definitivamente no es privado
  • no necesariamente nuevo
  • se puede acceder fuera del paquete (o ámbito léxico) con el espacio de nombres calificado, como $package_name::variable.


Declarar una variable con le ourpermite predefinir variables para usarlas use strictsin 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 $xdentro package maines $main::x. La declaración le our $xpermite usar la $xvariable básica sin penalización (es decir, sin un error resultante), en el alcance de la declaración, cuando el script usa use stricto use strict "vars". El alcance puede ser uno, o dos, o más paquetes, o un bloque pequeño.

Fran Corpier
fuente
2
Entonces, ¿cómo difiere nuestro local?
Nathan Fellman el
17
@Nathan Fellman, localno crea variables. No se relaciona con myy ouren absoluto. localrespalda temporalmente el valor de la variable y borra su valor actual.
ikegami
1
ourLas variables no son variables de paquete. No son de ámbito global, sino variables de ámbito léxico al igual que las myvariables. 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 ourse compiló.
ikegami
60

Los enlaces PerlMonks y PerlDoc de cartman y Olafur son una gran referencia: a continuación se muestra mi resumen:

mylas 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.

ourlas variables se definen dentro de un paquete / archivo y son accesibles desde cualquier código que useo requireese paquete / archivo: los conflictos de nombre se resuelven entre paquetes anteponiendo el espacio de nombres apropiado.

Solo para redondearlo, las localvariables tienen un alcance "dinámico", que difiere de las myvariables en que también son accesibles desde subrutinas llamadas dentro del mismo bloque.

bubaker
fuente
+1 para "las myvariables tienen un alcance [...] léxico dentro del mismo archivo si no están en {}s". Eso fue útil para mí, gracias.
Georg
48

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";
FMc
fuente
11

Hacer frente a Scoping es una buena descripción de las reglas de alcance de Perl. Es lo suficientemente viejo que ourno 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.

daotoad
fuente
5

myse usa para variables locales, mientras que ourse usa para variables globales.

Más lectura en Variable Scoping en Perl: lo básico .

ismail
fuente
16
Tenga cuidado al pronunciar las palabras local y global. Los términos adecuados son léxico y paquete. No puede crear verdaderas variables globales en Perl, pero algunas ya existen como $ _, y local se refiere a variables de paquete con valores localizados (creados por local), no a variables léxicas (creadas con my).
Chas. Owens
${^Potato}es global Se refiere a la misma variable independientemente de dónde la use.
MJD
5

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.

$varno está definido, lo que significa que local $var;es solo una declaración! Antes de usar localpara 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. $vares 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.

Xu Ding
fuente
Más información sobre ["recordar [$ a y $ b en] ordenar" aquí] ( stackoverflow.com/a/26128328/1028230 ). Perl nunca deja de ... asombrarme.
ruffin
4

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.

Ólafur Waage
fuente
2

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'.

Misha Gale
fuente
1
No tan. $ foo $ {foo} $ {'foo'} $ {"foo"} todos funcionan de la misma manera para asignación variable o desreferenciación. Cambiar el nuestro en el ejemplo anterior por mi sí funciona. Lo que probablemente experimentó fue tratar de desreferenciar $ foo como una variable de paquete, como $ main :: foo o $ :: foo, que solo funcionará para paquetes globales, como los definidos con nuestro .
Cosmicnet
Recién volví a probar usando v5.20, y definitivamente no da el mismo resultado con mi (imprime BAR dos veces)
Misha Gale
1
Mi prueba (en Windows): 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.
Cosmicnet
1
$ {"main :: foo"}, $ {":: foo"} y $ main :: foo son lo mismo que $ {"foo"}. La abreviatura es un 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.
Cosmicnet
0
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.
Lavi Buchnik
fuente
Proporcione algún tipo de explicación. Volcar código como este rara vez se considera apropiado.
Scott Solmer
en palabras simples: Nuestro (como el nombre dice) es una declinación variable para usar esa variable desde cualquier lugar en el script (función, bloque, etc.), cada variable por defecto (en caso de que no se declare) pertenece a "main" paquete, nuestra variable aún se puede usar incluso después de la eliminación de otro paquete en el script. La variable "my" en caso de que se declare en un bloque o función, solo se puede usar en ese bloque / función. en caso de que la variable "my" se declare no cerrada en un bloque, se puede usar en cualquier lugar del scriot, en un bloque cerrado o en una función como "nuestra" variable, pero no se puede usar en caso de que el paquete cambie
Lavi Buchnik
Mi script anterior muestra que por defecto estamos en el paquete "principal", luego el script imprime una "nuestra" variable del paquete "principal" (no cerrado en un bloque), luego declaramos dos "mi" variables en una función y imprimirlos desde esa función. luego imprimimos una variable "nuestra" desde otra función para mostrar que se puede usar en una función. luego cambiamos el paquete a "cambiado" (ya no "principal") e imprimimos nuevamente la variable "nuestro" con éxito. luego intento imprimir una variable "my" fuera de la función y falló. el script solo muestra la diferencia entre el uso "nuestro" y "mi".
Lavi Buchnik
0

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";
Yugdev
fuente
Esto explica la diferencia entre mi y nuestro. La variable my sale del alcance fuera de las llaves y se recolecta basura, pero la variable aún vive.
Yugdev
-1
#!/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;
xoid
fuente
¿Puedes explicar qué pretende demostrar este código? ¿Por qué son oury mydiferentes? ¿Cómo lo muestra este ejemplo?
Nathan Fellman
-1

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:

Evgeniy
fuente