Qual é a diferença entre 'my' e 'our' em Perl?

188

Eu sei o que myhá em Perl. Ele define uma variável que existe apenas no escopo do bloco em que está definida. O que ourfaz?

Como é que ourdifere my?

Nathan Fellman
fonte

Respostas:

215

Ótima pergunta: como ourdifere mye o que ourfaz?

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:

  • privado
  • Novo
  • não global
  • separado de qualquer pacote, para que a variável não possa ser acessada no formato de $package_name::variable.


Por outro lado, ourvariáveis ​​são variáveis ​​de pacote e, portanto, automaticamente:

  • variáveis globais
  • definitivamente não é privado
  • não necessariamente novo
  • pode ser acessado fora do pacote (ou escopo lexical) com o espaço para nome qualificado, como $package_name::variable.


Declarar uma variável com ourpermite pré-declarar variáveis ​​para usá-las use strictsem 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 $xinside package mainé $main::x. Declarar our $xpermite que você use a $xvariável bare sem penalidade (ou seja, sem erro resultante), no escopo da declaração, quando o script usa use strictor use strict "vars". O escopo pode ser um ou dois ou mais pacotes ou um pequeno bloco.

Fran Corpier
fonte
2
Então, como é que o nosso difere do local?
23711 Nathan Fellman
17
@ Nathan Fellman, localnão cria variáveis. Ele não se relaciona com mye ourem tudo. localfaz backup temporário do valor da variável e limpa seu valor atual.
Ikegami
1
ourvariáveis ​​não são variáveis ​​de pacote. Eles não têm escopo global, mas variáveis ​​de escopo lexical como as myvariá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 ourcompilação foi compilada.
Ikegami #
60

Os links PerlMonks e PerlDoc da cartman e Olafur são uma ótima referência - abaixo está minha rachadura em um resumo:

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

ouras variáveis ​​têm o escopo definido dentro de um pacote / arquivo e acessíveis a partir de qualquer código que useou requireaquele conflito de nome do pacote / arquivo seja resolvido entre os pacotes, precedendo o espaço de nome apropriado.

Para finalizar, as localvariáveis ​​têm escopo "dinâmico", diferindo das myvariáveis, pois também são acessíveis a partir de sub-rotinas chamadas dentro do mesmo bloco.

bubaker
fonte
+1 para " myvariáveis ​​têm escopo lexicamente [...] dentro do mesmo arquivo, se não em {}s". Isso foi útil para mim, obrigado.
Georg
48

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

Lidar com o escopo é uma boa visão geral das regras de escopo do Perl. É velho o suficiente para ournã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.

daotoad
fonte
5

myé usado para variáveis ​​locais, enquanto que ouré usado para variáveis ​​globais.

Leia mais em Variable Scoping in Perl: the basic .

ismail
fonte
16
Tenha cuidado ao usar as palavras local e global. Os termos adequados são lexicais e pacote. Você não pode criar variáveis ​​globais verdadeiras no Perl, mas algumas já existem como $ _, e local refere-se a variáveis ​​de pacote com valores localizados (criados por local), e não a variáveis ​​lexicais (criadas com my).
Chas. Owens
${^Potato}é global. Refere-se à mesma variável, independentemente de onde você a usa.
MJD 07/07
5

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.

$varnão está definido, o que significa que local $var;é apenas uma declaração! Antes de usar localpara 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.

Xu Ding
fonte
Mais sobre ["lembrando de [$ a e $ b in] classificar" aqui] ( stackoverflow.com/a/26128328/1028230 ). Perl nunca deixa de me humilhar.
Ruffin
4

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.

Ólafur Waage
fonte
2

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

Misha Gale
fonte
1
Não tão. $ foo $ {foo} $ {'foo'} $ {"foo"} funcionam da mesma forma para atribuição de variáveis ​​ou desreferenciamento. Trocar o nosso no exemplo acima para o meu funciona. O que você provavelmente experimentou foi tentar desreferenciar $ foo como uma variável de pacote, como $ main :: foo ou $ :: foo, que funcionará apenas para globais de pacotes, como os definidos com o nosso .
precisa saber é o seguinte
Apenas reanalisada usando v5.20, e definitivamente não dá o mesmo resultado com o meu (ele imprime BAR duas vezes.)
Misha Gale
1
Meu teste (no Windows): 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.
Cosmicnet
1
$ {"main :: foo"}, $ {":: foo"} e $ main :: foo são os mesmos que $ {"foo"}. A abreviação é sensível a pacotes 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.
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";

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.
Lavi Buchnik
fonte
Por favor, forneça algum tipo de explicação. Despejar códigos como esse raramente é considerado apropriado.
Scott Solmer
em palavras simples: Nossa (como o nome sais) é uma declaração de variável para usar essa variável de qualquer lugar no script (função, bloco, etc ...), todas as variáveis ​​por padrão (no caso não declaradas) pertencem a "main" pacote, nossa variável ainda pode ser usada mesmo após a declaração de outro pacote no script. A variável "my", no caso declarado em um bloco ou função, pode ser usada apenas nesse bloco / função. caso a variável "my" tenha sido declarada não fechada em um bloco, ela pode ser usada em qualquer lugar do scriot, em um bloco fechado ou em uma função como a variável "our", mas não pode ser usada no caso de o pacote mudar
Lavi Buchnik
Meu script acima mostra que, por padrão, estamos no pacote "main", então o script imprime uma variável "our" do pacote "main" (não fechado em um bloco), e declaramos duas variáveis ​​"my" em uma função e imprima-os a partir dessa função. depois imprimimos uma variável "our" de outra função para mostrar que ela pode ser usada em uma função. depois alteramos o pacote para "alterado" (não "principal" não mais) e imprimimos novamente a variável "our" com êxito. tentando imprimir uma variável "my" fora da função e falhou. o script apenas mostrando a diferença entre o uso "nosso" e "meu".
Lavi Buchnik
0

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";
Yugdev
fonte
Isso explica a diferença entre o meu e o nosso. A variável my sai do escopo fora do aparelho e é coletada como lixo, mas a nossa variável ainda 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
fonte
Você pode explicar o que esse código pretende demonstrar? Por que são oure mydiferentes? Como este exemplo mostra isso?
Nathan Fellman
-1

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:

Evgeniy
fonte