В чем разница между «моим» и «нашим» в Perl?


188

Я знаю, что myесть в Perl. Он определяет переменную, которая существует только в области действия блока, в котором она определена. Что делает our?

Чем ourотличается от my?

Ответы:


215

Большой вопрос: чем ourотличается myи чем отличается our?

В итоге:

Доступный начиная с Perl 5, myэто способ объявления непакетных переменных, которые:

  • частный
  • новый
  • неглобальный
  • отдельно от любого пакета, так что переменная не может быть доступна в виде $package_name::variable.


С другой стороны, ourпеременные являются переменными пакета, и поэтому автоматически:

  • глобальные переменные
  • определенно не частный
  • не обязательно новый
  • можно получить доступ за пределами пакета (или лексической области) с помощью квалифицированного пространства имен, как $package_name::variable.


Объявление переменной с помощью ourпозволяет вам предварительно объявить переменные, чтобы использовать их use strictбез получения предупреждений об опечатках или ошибок времени компиляции. Начиная с Perl 5.6, он заменил устаревшее use vars, которое было только областью файла, а не лексически, как есть our.

Например, формальное квалифицированное имя для переменной $xвнутри package main- это $main::x. Объявление our $xпозволяет использовать пустую $xпеременную без штрафа (т. Е. Без возникающей ошибки) в области объявления, когда сценарий использует use strictили use strict "vars". Область действия может быть одним, двумя или несколькими пакетами или одним небольшим блоком.


2
Так чем же отличается наш от местного?
Натан Феллман

17
@ Натан Феллман, localне создает переменных. Это не относится myи ourвообще. localвременно создает резервную копию значения переменной и очищает ее текущее значение.
Икегами

1
ourпеременные не являются пакетными переменными. Они не глобальные, а переменные лексического масштаба, как myпеременные. Вы можете видеть , что в следующей программе: package Foo; our $x = 123; package Bar; say $x;. Если вы хотите «объявить» переменную пакета, вам нужно использовать use vars qw( $x );. our $x;объявляет переменную с лексической областью, которая связывается с переменной с тем же именем в пакете, в котором она ourбыла скомпилирована.
икегами

60

Ссылки PerlMonks и PerlDoc от Cartman и Olafur являются отличным справочным материалом. Ниже приведена моя краткая сводка:

myпеременные лексически ограничены в пределах одного блока, определенного {}или внутри одного и того же файла, если не в {}s. Они не доступны из пакетов / подпрограмм, определенных вне одной лексической области видимости / блока.

ourпеременные в области видимости пакета / файл и доступны из любого кода, useили requireчто пакет / файл - конфликты имен разрешаются между пакетами, предваряя соответствующее пространство имен.

Просто для округления, localпеременные «динамически» ограничены, отличаясь от myпеременных тем, что они также доступны из подпрограмм, вызываемых в одном и том же блоке.


+1 для " myпеременных лексически ограничены [...] в одном и том же файле, если не в {}s". Это было полезно для меня, спасибо.
Георг

48

Пример:

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";

11

Справиться со Scoping - хороший обзор правил Perl. Это достаточно старое, что ourне обсуждается в основной части текста. Он рассматривается в разделе « Примечания » в конце.

В статье рассказывается о переменных пакета и динамической области видимости, а также о том, чем они отличаются от лексических переменных и лексической области видимости.


5

myиспользуется для локальных переменных, тогда ourкак используется для глобальных переменных.

Подробнее читайте в Variable Scoping в Perl: основы .


16
Будьте осторожны, подбрасывая слова локальные и глобальные. Правильные термины являются лексическими и пакетными. Вы не можете создать настоящие глобальные переменные в Perl, но некоторые уже существуют, например, $ _, а локальный относится к переменным пакета с локализованными значениями (созданными локальными), а не к лексическим переменным (созданным с помощью my).
час. Оуэнс

${^Potato}является глобальным. Он ссылается на одну и ту же переменную независимо от того, где вы ее используете.
MJD

5

Я когда-либо встречал некоторые подводные камни в лексических декларациях в Perl, которые меня расстроили, которые также связаны с этим вопросом, поэтому я просто добавлю свое резюме здесь:

1. Определение или декларация?

local $var = 42;
print "var: $var\n";

Выход есть var: 42. Однако мы не могли сказать, local $var = 42;является ли это определение или декларация. Но как насчет этого:

use strict;
use warnings;

local $var = 42;
print "var: $var\n";

Вторая программа выдаст ошибку:

Global symbol "$var" requires explicit package name.

$varне определено, что означает local $var;просто объявление! Прежде чем использовать localдля объявления переменной, убедитесь, что она определена как глобальная переменная ранее.

Но почему это не подведет?

use strict;
use warnings;

local $a = 42;
print "var: $a\n";

Выход: var: 42.

Это потому $a, что $bглобальная переменная предопределена в Perl. Помните функцию сортировки ?

2. Лексический или глобальный?

Я был программистом на C до того, как начал использовать Perl, поэтому концепция лексических и глобальных переменных кажется мне простой: она просто соответствует auto и внешним переменным в C. Но есть небольшие различия:

В C внешняя переменная - это переменная, определенная вне любого функционального блока. С другой стороны, автоматическая переменная - это переменная, определенная внутри функционального блока. Как это:

int global;

int main(void) {
    int local;
}

В Perl все тонко:

sub main {
    $var = 42;
}

&main;

print "var: $var\n";

Выход есть var: 42. $varявляется глобальной переменной, даже если она определена в функциональном блоке! На самом деле в Perl любая переменная объявляется как глобальная по умолчанию.

Урок состоит в том, чтобы всегда добавлять use strict; use warnings;в начале Perl-программу, что заставит программиста явно объявлять лексическую переменную, чтобы мы не ошиблись из-за некоторых ошибок, принимаемых как должное.


Подробнее о [«запоминании [$ a и $ b in] sort» здесь] ( stackoverflow.com/a/26128328/1028230 ). Perl не перестает удивлять меня.
Ерф

4

У perldoc есть хорошее определение нашего.

В отличие от my, который одновременно выделяет хранилище для переменной и ассоциирует простое имя с этим хранилищем для использования в текущей области, наши связывают простое имя с переменной пакета в текущем пакете для использования в текущей области. Другими словами, у наших правил те же, что и у my, но необязательно создавать переменную.


2

Это только отчасти связано с вопросом, но я только что обнаружил (для меня) непонятный бит синтаксиса perl, который вы можете использовать с «нашими» (пакетными) переменными, которые вы не можете использовать с «моим» (локальным) переменные.

#!/usr/bin/perl

our $foo = "BAR";

print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";

Вывод:

BAR
BAZ

Это не сработает, если вы измените «наш» на «мой».


1
Не так. $ foo $ {foo} $ {'foo'} $ {"foo"} работают одинаково для назначения переменных или разыменования. Обмен наш в приведенном выше примере для моей работы. Вероятно, вы пытались разыменовать $ foo как переменную пакета, такую ​​как $ main :: foo или $ :: foo, которая будет работать только для глобальных переменных пакета, таких как определенные с нашими .
Cosmicnet

Только что проверил, используя v5.20, и он определенно не дает тот же результат с моим (он печатает BAR дважды.)
Миша Гейл

1
Мой тест (на окнах): 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 Таким образом, в моем тестировании я попал в ту же ловушку. $ {foo} аналогично $ foo, скобки полезны при интерполяции. $ {"foo"} на самом деле выглядит как $ main :: {}, который является главной таблицей символов, так как он содержит только переменные области видимости пакета.
Cosmicnet

1
$ {"main :: foo"}, $ {":: foo"} и $ main :: foo совпадают с $ {"foo"}. Сокращение относится к пакетно-чувствительным perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"работам, так как в этом контексте $ {"foo"} теперь равно $ {"test :: foo"}. О символьных таблицах и глобусах есть некоторая информация об этом, как и книга по программированию на Advanced Perl. Извините за мою предыдущую ошибку.
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";

Будет выводить это:

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 

В случае использования «use strict» вы получите этот сбой при попытке запустить скрипт:

Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.

Пожалуйста, предоставьте какое-нибудь объяснение. Подобный дамп код редко считается подходящим.
Скотт Солмер

Проще говоря: наша (как и имя sais) - это переменная, в которой запрещено использовать эту переменную из любого места в скрипте (функции, блока и т. д.), каждая переменная по умолчанию (в случае, если она не объявлена) принадлежит «main» package, наша переменная все еще может использоваться даже после объявления другого пакета в сценарии. Переменная my в случае, объявленном в блоке или функции, может использоваться только в этом блоке / функции. если переменная "my" была объявлена ​​не закрытой в блоке, она может использоваться в любом месте в scriot, в закрытом блоке или в функции как переменная "our", но не может использоваться в случае изменения пакета
Лави Бучник,

Мой скрипт выше показывает, что по умолчанию мы находимся в «основном» пакете, затем скрипт печатает «нашу» переменную из «основного» пакета (не закрытого в блоке), затем мы объявляем две «мои» переменные в функции и распечатать их из этой функции. затем мы печатаем «нашу» переменную из другой функции, чтобы показать, что ее можно использовать в функции. затем мы меняем пакет на «измененный» (больше не «основной») и снова успешно печатаем переменную «наш». затем попытка напечатать переменную «my» вне функции и не удалась. скрипт, просто показывающий разницу между «нашим» и «моим» использованием.
Лави Бучник,

0

Просто попробуйте использовать следующую программу:

#!/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";

Это объясняет разницу между моим и нашим. Переменная my выходит за рамки фигурных скобок и собирается сборщиком мусора, но наша переменная все еще живет.
Югдев

-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;

Можете ли вы объяснить, что этот код предназначен для демонстрации? Почему бывают ourи myразные? Как этот пример показывает это?
Натан Феллман

-1

Давайте подумаем, что такое интерпретатор на самом деле: это кусок кода, который хранит значения в памяти и позволяет командам в программе, которые он интерпретирует, получать доступ к этим значениям по их именам, которые указаны внутри этих инструкций. Таким образом, большая задача интерпретатора состоит в том, чтобы сформировать правила использования имен в этих инструкциях для доступа к значениям, которые хранит интерпретатор.

При обнаружении «my» интерпретатор создает лексическую переменную: именованное значение, к которому интерпретатор может получить доступ только во время выполнения блока и только из этого синтаксического блока. При обнаружении «нашего» интерпретатор создает лексический псевдоним переменной пакета: он связывает имя, которое интерпретатор должен с тех пор обрабатывать как имя лексической переменной, пока блок не будет завершен, со значением пакета. переменная с тем же именем.

В результате вы можете притворяться, что используете лексическую переменную, и обходить правила «строгого использования» при полной квалификации переменных пакета. Поскольку интерпретатор автоматически создает переменные пакета при их первом использовании, побочным эффектом использования «нашего» также может быть то, что интерпретатор также создает переменную пакета. В этом случае создаются две вещи: переменная пакета, к которой интерпретатор может получить доступ отовсюду, при условии, что она правильно обозначена в соответствии с запросом 'use strict' (с добавлением имени ее пакета и двух двоеточий) и ее лексическим псевдонимом.

Источники:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.