Eu sei o que my
há em Perl. Ele define uma variável que existe apenas no escopo do bloco em que está definida. O que our
faz?
Como é que our
difere my
?
Eu sei o que my
há em Perl. Ele define uma variável que existe apenas no escopo do bloco em que está definida. O que our
faz?
Como é que our
difere my
?
Respostas:
Ótima pergunta: como our
difere my
e o que our
faz?
Em suma:
Disponível desde o Perl 5, my
é uma maneira de declarar variáveis que não são de pacote, que são:
$package_name::variable
.Por outro lado, our
variáveis são variáveis de pacote e, portanto, automaticamente:
$package_name::variable
.Declarar uma variável com our
permite pré-declarar variáveis para usá-las use strict
sem receber avisos de erro de digitação ou erros em tempo de compilação. Desde o Perl 5.6, ele substituiu o obsoleto use vars
, que tinha apenas escopo de arquivo e não lexicamente como está our
.
Por exemplo, o nome formal e qualificado para a variável $x
inside package main
é $main::x
. Declarar our $x
permite que você use a $x
variável bare sem penalidade (ou seja, sem erro resultante), no escopo da declaração, quando o script usa use strict
or use strict "vars"
. O escopo pode ser um ou dois ou mais pacotes ou um pequeno bloco.
local
não cria variáveis. Ele não se relaciona com my
e our
em tudo. local
faz backup temporário do valor da variável e limpa seu valor atual.
our
variáveis não são variáveis de pacote. Eles não têm escopo global, mas variáveis de escopo lexical como as my
variáveis. Você pode ver que o seguinte programa: package Foo; our $x = 123; package Bar; say $x;
. Se você quiser "declarar" uma variável do pacote, precisará usar use vars qw( $x );
. our $x;
declara uma variável de escopo lexicamente alias à variável com o mesmo nome no pacote em que a our
compilação foi compilada.
Os links PerlMonks e PerlDoc da cartman e Olafur são uma ótima referência - abaixo está minha rachadura em um resumo:
my
as variáveis têm escopo lexicamente dentro de um único bloco definido por {}
ou dentro do mesmo arquivo, se não em {}
s. Eles não são acessíveis a partir de pacotes / sub-rotinas definidas fora do mesmo escopo / bloco lexical.
our
as variáveis têm o escopo definido dentro de um pacote / arquivo e acessíveis a partir de qualquer código que use
ou require
aquele conflito de nome do pacote / arquivo seja resolvido entre os pacotes, precedendo o espaço de nome apropriado.
Para finalizar, as local
variáveis têm escopo "dinâmico", diferindo das my
variáveis, pois também são acessíveis a partir de sub-rotinas chamadas dentro do mesmo bloco.
my
variáveis têm escopo lexicamente [...] dentro do mesmo arquivo, se não em {}
s". Isso foi útil para mim, obrigado.
Um exemplo:
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";
Lidar com o escopo é uma boa visão geral das regras de escopo do Perl. É velho o suficiente para our
não ser discutido no corpo do texto. É abordada na seção Notas no final.
O artigo fala sobre variáveis de pacote e escopo dinâmico e como isso difere de variáveis lexicais e escopo lexical.
my
é usado para variáveis locais, enquanto que our
é usado para variáveis globais.
Leia mais em Variable Scoping in Perl: the basic .
${^Potato}
é global. Refere-se à mesma variável, independentemente de onde você a usa.
Eu já conheci algumas armadilhas sobre declarações lexicais no Perl que me atrapalharam, que também estão relacionadas a essa pergunta, então apenas adiciono meu resumo aqui:
1. Definição ou declaração?
local $var = 42;
print "var: $var\n";
A saída é var: 42
. No entanto, não sabemos se local $var = 42;
é uma definição ou declaração. Mas e quanto a isso:
use strict;
use warnings;
local $var = 42;
print "var: $var\n";
O segundo programa lançará um erro:
Global symbol "$var" requires explicit package name.
$var
não está definido, o que significa que local $var;
é apenas uma declaração! Antes de usar local
para declarar uma variável, verifique se ela está definida como uma variável global anteriormente.
Mas por que isso não irá falhar?
use strict;
use warnings;
local $a = 42;
print "var: $a\n";
A saída é: var: 42
.
Isso porque $a
, além de $b
, é uma variável global predefinida no Perl. Lembre-se da função de classificação ?
2. Lexical ou global?
Eu era um programador C antes de começar a usar o Perl, então o conceito de variáveis lexicais e globais parece direto para mim: apenas corresponde a variáveis automáticas e externas em C. Mas há pequenas diferenças:
Em C, uma variável externa é uma variável definida fora de qualquer bloco de função. Por outro lado, uma variável automática é uma variável definida dentro de um bloco de funções. Como isso:
int global;
int main(void) {
int local;
}
Enquanto em Perl, as coisas são sutis:
sub main {
$var = 42;
}
&main;
print "var: $var\n";
A saída é var: 42
. $var
é uma variável global, mesmo que esteja definida em um bloco de funções! Na verdade, em Perl, qualquer variável é declarada como global por padrão.
A lição é sempre adicionar use strict; use warnings;
no início de um programa Perl, o que forçará o programador a declarar explicitamente a variável lexical, para que não fiquemos confusos com alguns erros tomados como garantidos.
O perldoc tem uma boa definição de nossa.
Ao contrário de my, que aloca armazenamento para uma variável e associa um nome simples a esse armazenamento para uso no escopo atual, nosso associa um nome simples a uma variável de pacote no pacote atual, para uso dentro do escopo atual. Em outras palavras, nossa possui as mesmas regras de escopo que a minha, mas não cria necessariamente uma variável.
Isso está apenas um pouco relacionado à questão, mas eu acabei de descobrir um bit obscuro (para mim) de sintaxe perl que você pode usar com variáveis "our" (package) que você não pode usar com "my" (local) variáveis.
#!/usr/bin/perl
our $foo = "BAR";
print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";
Resultado:
BAR
BAZ
Isso não funcionará se você alterar 'nosso' para 'meu'.
perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo"
output: barbaz
perl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo"
output: barbaz
perl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
output: barbar
Então, em meus testes, caí na mesma armadilha. $ {foo} é o mesmo que $ foo, os colchetes são úteis ao interpolar. $ {"foo"} é, na verdade, uma consulta a $ main :: {}, que é a tabela principal de símbolos, pois contém apenas variáveis com escopo definido no pacote.
perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
, pois neste contexto $ {"foo"} agora é igual a $ {"test :: foo"}. Of Symbol Tables and Globs tem algumas informações, assim como o livro de programação Advanced Perl. Desculpe pelo meu erro 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";
Saída isso:
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
No caso de usar "use strict", ocorrerá esta falha ao tentar executar o script:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
Apenas tente usar o seguinte 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
e my
diferentes? Como este exemplo mostra isso?
Vamos pensar o que realmente é um intérprete: é um pedaço de código que armazena valores na memória e permite que as instruções em um programa que ele interpreta acessem esses valores por seus nomes, especificados nessas instruções. Portanto, o grande trabalho de um intérprete é moldar as regras de como devemos usar os nomes nessas instruções para acessar os valores que o intérprete armazena.
Ao encontrar "meu", o intérprete cria uma variável lexical: um valor nomeado que o intérprete pode acessar apenas enquanto executa um bloco e somente dentro desse bloco sintático. Ao encontrar "our", o intérprete cria um alias lexical de uma variável do pacote: vincula um nome, que o intérprete deve processar a partir de então como o nome de uma variável lexical, até o término do bloco, ao valor do pacote variável com o mesmo nome.
O efeito é que você pode fingir que está usando uma variável lexical e ignorar as regras de 'use strict' na qualificação completa das variáveis de pacote. Como o intérprete cria automaticamente variáveis de pacote quando elas são usadas pela primeira vez, o efeito colateral de usar "our" também pode ser que o intérprete crie também uma variável de pacote. Nesse caso, duas coisas são criadas: uma variável de pacote, que o intérprete pode acessar de qualquer lugar, desde que seja adequadamente designada conforme solicitado por 'use strict' (precedido com o nome de seu pacote e dois pontos) e seu alias lexical.
Fontes: