Я знаю, що my
в Perl. Він визначає змінну, яка існує лише в області блоку, в якому вона визначена. Що робить our
?
Чим our
відрізняється від my
?
Я знаю, що my
в Perl. Він визначає змінну, яка існує лише в області блоку, в якому вона визначена. Що робить our
?
Чим our
відрізняється від my
?
Відповіді:
Відмінне запитання: чим 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"
. Об'єм може бути одним, або двома, або більше пакетами, або одним невеликим блоком.
local
не створює змінних. Це не стосується my
і our
зовсім. local
тимчасово створює резервну копію значення змінної та очищає її поточне значення.
our
змінні не є змінними пакетів. Вони не є загальносвітовими, а лексично-охопленими змінними, як і my
змінні. Ви можете бачити , що в наступній програмі: package Foo; our $x = 123; package Bar; say $x;
. Якщо ви хочете "оголосити" змінну пакету, вам потрібно скористатися use vars qw( $x );
. our $x;
оголошує змінну з лексичним діапазоном, яка є псевдонімом однойменної змінної в пакеті, в який our
було складено.
Посилання PerlMonks та PerlDoc від Cartman та Olafur є чудовою орієнтиром - нижче мою тріщину підсумовано:
my
змінні охоплюються лексично в межах одного блоку, визначеного {}
або в одному файлі, якщо не в {}
s. Вони недоступні через пакети / підпрограми, визначені поза тим же лексичним діапазоном / блоком.
our
змінні розміщуються в межах пакету / файлу і доступні з будь-якого коду, який use
або require
той пакет пакету / файлу конфлікту імен вирішуються між пакетами, попередньо додавши відповідну область імен.
Просто для її округлення local
змінні "динамічно" охоплюються, що відрізняється від my
змінних тим, що вони також доступні з підпрограм, викликаних в одному блоці.
my
змінні охоплюються лексично [...] в межах одного файлу, якщо не в {}
s". Це було корисно для мене, дякую.
Приклад:
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";
Впоратися із визначенням масштабу - це хороший огляд правил визначення області Perl. Він досить старий, що our
не обговорюється в тілі тексту. Він розглядається в розділі Примітки наприкінці.
У статті йдеться про змінні пакету та динамічний обсяг, а також про те, чим вони відрізняються від лексичних змінних та лексичних областей.
my
використовується для локальних змінних, тоді our
як використовується для глобальних змінних.
Більше читання на сайті Variable Scoping в Perl: основи .
${^Potato}
є глобальним. Він відноситься до тієї ж змінної незалежно від того, де ви її використовуєте.
Я коли-небудь зустрічав деякі підводні камені щодо лексичних декларацій в 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. Лексичні чи глобальні?
Перед початком використання Perl я був програмістом на C, тому поняття лексичних та глобальних змінних мені здається простим: воно просто відповідає автоматичним та зовнішнім змінним у 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, що змусить програміста чітко оголосити лексичну змінну, щоб ми не заплутувались через деякі помилки, сприйняті як належне.
Perldoc має гарне визначення наших.
На відміну від мого, який обидва виділяє сховище для змінної і пов'язує просте ім'я з цим сховищем для використання в поточному діапазоні, ми пов'язуємо просте ім'я зі змінною пакета в поточному пакеті для використання в поточному масштабі. Іншими словами, у нас є ті ж правила розміщення, що і у мене, але не обов'язково створювати змінну.
Це лише дещо пов'язане з питанням, але я щойно виявив (мені) незрозумілий біт синтаксису perl, який ви можете використовувати з "нашими" (пакетними) змінними, які ви не можете використовувати з "моїм" (локальним) змінні.
#!/usr/bin/perl
our $foo = "BAR";
print $foo . "\n";
${"foo"} = "BAZ";
print $foo . "\n";
Вихід:
BAR
BAZ
Це не спрацює, якщо ви зміните "наше" на "моє".
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 :: {}, яка є основною таблицею символів, оскільки така містить лише змінні, розміщені в пакеті.
perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo"
роботи, оскільки в цьому контексті $ {"foo"} тепер дорівнює $ {"test :: foo"}. Про Symbol Tables and Globs є деяка інформація про нього, як і книга програмування Advanced Perl. Вибачте за мою попередню помилку.
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
У разі використання "строгого використання" ця помилка отримає при спробі запуску сценарію:
Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
Execution of ./check_global.pl aborted due to compilation errors.
Просто спробуйте використати таку програму:
#!/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
і my
різні? Як це показує цей приклад?
Давайте подумаємо, що насправді є інтерпретатором: це фрагмент коду, який зберігає значення в пам'яті та дає вказівки в програмі, що інтерпретує доступ до цих значень за їхніми іменами, які вказані всередині цих інструкцій. Отже, велика робота перекладача - формувати правила того, як ми повинні використовувати імена в цих інструкціях для доступу до значень, які зберігає перекладач.
Зустрічаючи "мій", інтерпретатор створює лексичну змінну: назване значення, до якого інтерпретатор може отримати доступ лише під час виконання блоку, і лише з цього синтаксичного блоку. Зустрічаючи "наше", інтерпретатор робить лексичний псевдонім змінної пакета: він пов'язує ім'я, яке інтерпретатор повинен згодом обробляти як ім'я лексичної змінної, поки блок не буде закінчений, до значення пакета змінна з тим же ім'ям.
Ефект полягає в тому, що ви можете зробити вигляд, що ви використовуєте лексичну змінну і обійти правила "строгого використання" щодо повної кваліфікації змінних пакетів. Оскільки інтерпретатор автоматично створює змінні пакета при їх першому використанні, побічним ефектом використання "наших" може бути також те, що інтерпретатор також створює змінну пакету. У цьому випадку створюються дві речі: змінна пакунка, до якої інтерпретатор може отримати доступ звідусіль, за умови, що вона належним чином позначена так, як цього вимагає "строго використовувати" (попередньо вказуючи назву свого пакета та дві колонки), і його лексичний псевдонім.
Джерела: