Perl Language
переменные
Поиск…
Синтаксис
- моя # Лексическая декларация
- наша глобальная декларация #
- $ foo # Скаляр
- @foo # Массив
- $ # foo # Массив Last-Index
- % foo # Хеш
- $ {$ foo} # Scalar De-Reference
- @ {$ foo} # Array De-Reference
- $ # {$ foo} # Array-DeRef Last-Index
- % {$ foo} # Hash De-Reference
- $ foo [$ index] # Массив индексируется
- $ {$ foo} [$ index] # Array De-Reference и индексируется.
- $ foo -> [$ index] # Array De-Reference и индексироваться (упрощено)
- $ foo {$ key} # Хеш получить значение для ключа
- $ {$ foo} {$ key} # Hash Dereference и получить значение для ключа
- $ foo -> {$ key} # Hash Dereference и получить значение для ключа (упрощенного)
- \ $ x # Ссылка на скаляр
- \ @x # Ссылка на массив
- \% x # Ссылка на хэш
- = [] # Ссылка на анонимный массив (Inline)
- = {} # Ссылка на анонимный хэш (Inline)
Скаляры
Скаляры - это самый базовый тип данных Perl. Они отмечены сигилой $
и содержат одно значение одного из трех типов:
- число (
3
,42
,3.141
и т. д.), - строка (
'hi'
,"abc"
и т. д.) - ссылка на переменную (см. другие примеры).
my $integer = 3; # number
my $string = "Hello World"; # string
my $reference = \$string; # reference to $string
Perl конвертирует между числами и строками «на лету» , исходя из того, что ожидает конкретный оператор.
my $number = '41'; # string '41'
my $meaning = $number + 1; # number 42
my $sadness = '20 apples'; # string '20 apples'
my $danger = $sadness * 2; # number '40', raises warning
При преобразовании строки в число Perl берет столько цифр от строки, сколько может, поэтому 20 apples
преобразуются в 20
в последней строке.
Исходя из того, хотите ли вы обрабатывать содержимое скаляра в виде строки или числа, вам нужно использовать разные операторы. Не смешивайте их.
# String comparison # Number comparison
'Potato' eq 'Potato'; 42 == 42;
'Potato' ne 'Pomato'; 42 != 24;
'Camel' lt 'Potato'; 41 < 42;
'Zombie' gt 'Potato'; 43 > 42;
# String concatenation # Number summation
'Banana' . 'phone'; 23 + 19;
# String repetition # Number multiplication
'nan' x 3; 6 * 7;
Попытка использования строковых операций над номерами не вызывает предупреждений; попытка использовать числовые операции для нечисловых строк. Имейте в виду, что некоторые нецифровые строки, такие как 'inf'
, 'nan'
, '0 but true'
считаются цифрами.
Массивы
Массивы хранят упорядоченную последовательность значений. Вы можете получить доступ к содержимому по индексу или перебрать их. Значения будут оставаться в том порядке, в котором вы их заполняли.
my @numbers_to_ten = (1,2,3,4,5,6,7,8,9,10); # More conveniently: (1..10)
my @chars_of_hello = ('h','e','l','l','o');
my @word_list = ('Hello','World');
# Note the sigil: access an @array item with $array[index]
my $second_char_of_hello = $chars_of_hello[1]; # 'e'
# Use negative indices to count from the end (with -1 being last)
my $last_char_of_hello = $chars_of_hello[-1];
# Assign an array to a scalar to get the length of the array
my $length_of_array = @chars_of_hello; # 5
# You can use $# to get the last index of an array, and confuse Stack Overflow
my $last_index_of_array = $#chars_of_hello; # 4
# You can also access multiple elements of an array at the same time
# This is called "array slice"
# Since this returns multiple values, the sigil to use here on the RHS is @
my @some_chars_of_hello = @chars_of_hello[1..3]; # ('H', 'e', 'l')
my @out_of_order_chars = @chars_of_hello[1,4,2]; # ('e', 'o', 'l')
# In Python you can say array[1:-1] to get all elements but first and last
# Not so in Perl: (1..-1) is an empty list. Use $# instead
my @empty_list = @chars_of_hello[1..-1]; # ()
my @inner_chars_of_hello = @chars_of_hello[1..$#chars_of_hello-1]; # ('e','l','l')
# Access beyond the end of the array yields undef, not an error
my $undef = $chars_of_hello[6]; # undef
Массивы изменяемы:
use utf8; # necessary because this snippet is utf-8
$chars_of_hello[1] = 'u'; # ('h','u','l','l','o')
push @chars_of_hello, ('!', '!'); # ('h','u','l','l','o','!','!')
pop @chars_of_hello; # ('h','u','l','l','o','!')
shift @chars_of_hello; # ('u','l','l','o','!')
unshift @chars_of_hello, ('¡', 'H'); # ('¡','H','u','l','l','o','!')
@chars_of_hello[2..5] = ('O','L','A'); # ('¡','H','O','L','A',undef,'!') whoops!
delete $chars_of_hello[-2]; # ('¡','H','O','L','A', '!')
# Setting elements beyond the end of an array does not result in an error
# The array is extended with undef's as necessary. This is "autovivification."
my @array; # ()
my @array[3] = 'x'; # (undef, undef, undef, 'x')
Наконец, вы можете перебрать содержимое массива:
use v5.10; # necessary for 'say'
for my $number (@numbers_to_ten) {
say $number ** 2;
}
При использовании в качестве булевых элементов массивы являются истинными, если они не пусты.
Хэш
Хэши можно понимать как таблицы поиска. Вы можете получить доступ к его содержимому, указав ключ для каждого из них. Ключи должны быть строками. Если это не так, они будут преобразованы в строки.
Если вы дадите хэш просто известный ключ, он будет служить вам вашей ценности.
# Elements are in (key, value, key, value) sequence
my %inhabitants_of = ("London", 8674000, "Paris", 2244000);
# You can save some typing and gain in clarity by using the "fat comma"
# syntactical sugar. It behaves like a comma and quotes what's on the left.
my %translations_of_hello = (spanish => 'Hola', german => 'Hallo', swedish => 'Hej');
В следующем примере обратите внимание на скобки и сигилы: вы получаете доступ к элементу %hash
с помощью $hash{key}
потому что значение, которое вы хотите, является скаляром. Некоторые считают хорошей практикой процитировать ключ, в то время как другие находят этот стиль визуально шумным. Цитирование требуется только для ключей, которые могут быть ошибочно приняты за выражения типа $hash{'some-key'}
my $greeting = $translations_of_hello{'spanish'};
В то время как Perl по умолчанию будет пытаться использовать просто слова как строки, +
модификатор также может использоваться для указания Perl, что ключ не должен быть интерполирован, а выполнен с результатом выполнения, используемым в качестве ключа:
my %employee = ( name => 'John Doe', shift => 'night' );
# this example will print 'night'
print $employee{shift};
# but this one will execute [shift][1], extracting first element from @_,
# and use result as a key
print $employee{+shift};
Подобно массивам, вы можете одновременно получить доступ к нескольким элементам хэша. Это называется хэш-срезом . Результирующее значение - это список, поэтому используйте @
sigil:
my @words = @translations_of_hello{'spanish', 'german'}; # ('Hola', 'Hallo')
Итерации по клавишам хэша с keys
keys
возвращают элементы в произвольном порядке. Совместимый с sort
, если вы хотите.
for my $lang (sort keys %translations_of_hello) {
say $translations_of_hello{$lang};
}
Если вам действительно не нужны такие ключи, как в предыдущем примере, values
возвращают values
хеша напрямую:
for my $translation (values %translations_of_hello) {
say $translation;
}
Вы также можете использовать цикл while, each
должен перебирать хэш. Таким образом, вы получите как ключ, так и значение в одно и то же время без отдельного поиска значений. Его использование, однако, обескураживает, так как each
может нарушить путаницу.
# DISCOURAGED
while (my ($lang, $translation) = each %translations_of_hello) {
say $translation;
}
Доступ к неустановленным элементам возвращает undef, а не ошибку:
my $italian = $translations_of_hello{'italian'}; # undef
map
и list flattening можно использовать для создания хэшей из массивов. Это популярный способ создания «набора» значений, например, чтобы быстро проверить, находится ли значение в @elems
. Эта операция обычно занимает время O (n) (т. Е. Пропорционально количеству элементов), но может выполняться в постоянное время (O (1)) путем превращения списка в хэш:
@elems = qw(x y x z t);
my %set = map { $_ => 1 } @elems; # (x, 1, y, 1, t, 1)
my $y_membership = $set{'y'}; # 1
my $w_membership = $set{'w'}; # undef
Это требует некоторого объяснения. Содержимое @elems
считывается в список, который обрабатывается map
. map
принимает блок кода, который вызывается для каждого значения его входного списка; значение элемента доступно для использования в $_
. Наш кодовый блок возвращает два элемента списка для каждого элемента ввода: $_
, входной элемент и 1
, только некоторое значение. Как только вы учитываете сглаживание списка, результатом является то, что map { $_ => 1 } @elems
превращает qw(xyxzt)
в (x => 1, y => 1, x => 1, z => 1, t => 1)
.
Поскольку эти элементы назначаются в хеш, нечетные элементы становятся хеш-ключами, а даже элементы становятся хеш-значениями. Когда ключ указан несколько раз в списке, который должен быть присвоен хэшу, выигрывает последнее значение. Это эффективно отменяет дубликаты.
Более быстрый способ превратить список в хэш использует назначение хэш-фрагмента. Он использует оператор x
чтобы умножить один элементный список (1)
на размер @elems
, поэтому для каждого из ключей в срезе с левой стороны есть 1
значение:
@elems = qw(x y x z t);
my %set;
@set{@elems} = (1) x @elems;
Следующее приложение хешей также использует тот факт, что хэши и списки часто могут быть взаимозаменяемы для реализации названных функций args:
sub hash_args {
my %args = @_;
my %defaults = (foo => 1, bar => 0);
my %overrides = (__unsafe => 0);
my %settings = (%defaults, %args, %overrides);
}
# This function can then be called like this:
hash_args(foo => 5, bar => 3); # (foo => 5, bar => 3, __unsafe ==> 0)
hash_args(); # (foo => 1, bar => 0, __unsafe ==> 0)
hash_args(__unsafe => 1) # (foo => 1, bar => 0, __unsafe ==> 0)
При использовании в качестве булевых хешей истинны, если они не пусты.
Скалярные ссылки
Ссылка - это скалярная переменная (одна префикс $
), которая «ссылается» на некоторые другие данные.
my $value = "Hello";
my $reference = \$value;
print $value; # => Hello
print $reference; # => SCALAR(0x2683310)
Чтобы получить указанные данные, вы удалите ссылку на него.
say ${$reference}; # Explicit prefix syntax
say $$reference; # The braces can be left out (confusing)
Новый синтаксис разыменования постфикса, доступный по умолчанию из v5.24
use v5.24;
say $reference->$*; # New postfix notation
Это «де-ссылочное значение» может быть затем изменено, как и исходная переменная.
${$reference} =~ s/Hello/World/;
print ${$reference}; # => World
print $value; # => World
Ссылка всегда правдивая - даже если значение, на которое оно ссылается, является ложным (например, 0
или ""
).
Возможно, вам понадобится Scalar Reference If:
Вы хотите передать строку в функцию и изменить ее для этой строки, не возвращая ее.
Вы хотите явно запретить Perl неявно копировать содержимое большой строки в какой-то момент передачи вашей функции (что особенно важно для старых Perls без строк копирования на запись)
Вы хотите устранить неоднозначные значения строк с определенным значением из строк, передающих контент, например:
- Disambiguate имя файла из содержимого файла
- Disambiguate возвратил содержимое из строки возвращаемой ошибки
Вы хотите реализовать облегченную внутреннюю объектную модель, где объекты, переданные вызывающему коду, не имеют видимых пользователем метаданных:
our %objects; my $next_id = 0; sub new { my $object_id = $next_id++; $objects{ $object_id } = { ... }; # Assign data for object my $ref = \$object_id; return bless( $ref, "MyClass" ); }
Ссылки на массивы
Массивные ссылки - это скаляры ( $
), которые относятся к массивам.
my @array = ("Hello"); # Creating array, assigning value from a list
my $array_reference = \@array;
Их можно создать более коротко:
my $other_array_reference = ["Hello"];
Изменение / использование ссылок на массивы требует разглашения их в первую очередь.
my @contents = @{ $array_reference }; # Prefix notation
my @contents = @$array_reference; # Braces can be left out
Новый синтаксис разыменования постфикса, доступный по умолчанию из v5.24
use v5.24;
my @contents = $array_reference->@*; # New postfix notation
При доступе к содержимому arrayref по индексу вы можете использовать синтаксический сахар ->
.
my @array = qw(one two three); my $arrayref = [ qw(one two three) ]
my $one = $array[0]; my $one = $arrayref->[0];
В отличие от массивов, arrayrefs может быть вложенным:
my @array = ( (1, 0), (0, 1) ) # ONE array of FOUR elements: (1, 0, 0, 1)
my @matrix = ( [1, 0], [0, 1] ) # an array of two arrayrefs
my $matrix = [ [0, 1], [1, 0] ] # an arrayref of arrayrefs
# There is no namespace conflict between scalars, arrays and hashes
# so @matrix and $matrix _both_ exist at this point and hold different values.
my @diagonal_1 = ($matrix[0]->[1], $matrix[1]->[0]) # uses @matrix
my @diagonal_2 = ($matrix->[0]->[1], $matrix->[1]->[0]) # uses $matrix
# Since chained []- and {}-access can only happen on references, you can
# omit some of those arrows.
my $corner_1 = $matrix[0][1]; # uses @matrix;
my $corner_2 = $matrix->[0][1]; # uses $matrix;
При использовании в качестве булева ссылки всегда верны.
Хэш-ссылки
Хеш-ссылки - это скаляры, содержащие указатель на ячейку памяти, содержащую данные хэша. Поскольку скаляр указывает непосредственно на сам хэш, когда он передается подпрограмме, изменения, сделанные в хэше, не являются локальными для подпрограммы, как при регулярном хэше, но вместо этого являются глобальными.
Сначала давайте рассмотрим, что происходит, когда вы передаете обычный хеш подпрограмме и изменяете ее внутри:
use strict;
use warnings;
use Data::Dumper;
sub modify
{
my %hash = @_;
$hash{new_value} = 2;
print Dumper("Within the subroutine");
print Dumper(\%hash);
return;
}
my %example_hash = (
old_value => 1,
);
modify(%example_hash);
print Dumper("After exiting the subroutine");
print Dumper(\%example_hash);
Результат:
$VAR1 = 'Within the subroutine';
$VAR1 = {
'new_value' => 2,
'old_value' => 1
};
$VAR1 = 'After exiting the subroutine';
$VAR1 = {
'old_value' => 1
};
Обратите внимание, что после выхода из подпрограммы хэш остается неизменным; все изменения в нем были локальными для подпрограммы изменения, потому что мы передали копию хэша, а не самого хэша.
Для сравнения, когда вы передаете hashref, вы передаете адрес исходному хешу, поэтому любые изменения, сделанные в подпрограмме, будут сделаны в исходном хэше:
use strict;
use warnings;
use Data::Dumper;
sub modify
{
my $hashref = shift;
# De-reference the hash to add a new value
$hashref->{new_value} = 2;
print Dumper("Within the subroutine");
print Dumper($hashref);
return;
}
# Create a hashref
my $example_ref = {
old_value => 1,
};
# Pass a hashref to a subroutine
modify($example_ref);
print Dumper("After exiting the subroutine");
print Dumper($example_ref);
Это приведет к:
$VAR1 = 'Within the subroutine';
$VAR1 = {
'new_value' => 2,
'old_value' => 1
};
$VAR1 = 'After exiting the subroutine';
$VAR1 = {
'new_value' => 2,
'old_value' => 1
};
Typeglobs, typeglob refs, дескрипторы файлов и константы
Типglob *foo
содержит ссылки на содержимое глобальных переменных с таким именем: $foo
, @foo
, $foo
, &foo
и т. Д. Вы можете получить к нему доступ как хэш и назначить непосредственно манипулировать таблицами символов (зло!).
use v5.10; # necessary for say
our $foo = "foo";
our $bar;
say ref *foo{SCALAR}; # SCALAR
say ${ *foo{SCALAR} }; # bar
*bar = *foo;
say $bar; # bar
$bar = 'egg';
say $foo; # egg
Typeglobs чаще обрабатываются при работе с файлами. open
, например, создает ссылку на типglob, когда его просят создать неглобальный дескриптор файла:
use v5.10; # necessary for say
open(my $log, '> utf-8', '/tmp/log') or die $!; # open for writing with encoding
say $log 'Log opened';
# You can dereference this globref, but it's not very useful.
say ref $log; # GLOB
say (*{$log}->{IO} // 'undef'); # undef
close $log or die $!;
Typeglobs также могут использоваться для создания глобальных переменных только для чтения, хотя use constant
используется более широко.
# Global constant creation
*TRUE = \('1');
our $TRUE;
say $TRUE; # 1
$TRUE = ''; # dies, "Modification of a read-only value attempted"
# use constant instead defines a parameterless function, therefore it's not global,
# can be used without sigils, can be imported, but does not interpolate easily.
use constant (FALSE => 0);
say FALSE; # 0
say &FALSE; # 0
say "${\FALSE}"; # 0 (ugh)
say *FALSE{CODE}; # CODE(0xMA1DBABE)
# Of course, neither is truly constant when you can manipulate the symbol table...
*TRUE = \('');
use constant (EVIL => 1);
*FALSE = *EVIL;
Sigils
Perl имеет ряд сигил:
$scalar = 1; # individual value
@array = ( 1, 2, 3, 4, 5 ); # sequence of values
%hash = ('it', 'ciao', 'en', 'hello', 'fr', 'salut'); # unordered key-value pairs
&function('arguments'); # subroutine
*typeglob; # symbol table entry
Они выглядят как сигилы, но не являются:
\@array; # \ returns the reference of what's on the right (so, a reference to @array)
$#array; # this is the index of the last element of @array
Вы можете использовать фигурные скобки после сигилы, если вы так склонны. Иногда это улучшает читаемость.
say ${value} = 5;
Хотя вы используете разные сигилы для определения переменных разных типов, к одной и той же переменной можно обращаться по-разному в зависимости от того, какие символы вы используете.
%hash; # we use % because we are looking at an entire hash
$hash{it}; # we want a single value, however, that's singular, so we use $
$array[0]; # likewise for an array. notice the change in brackets.
@array[0,3]; # we want multiple values of an array, so we instead use @
@hash{'it','en'}; # similarly for hashes (this gives the values: 'ciao', 'hello')
%hash{'it','fr'}; # we want an hash with just some of the keys, so we use %
# (this gives key-value pairs: 'it', 'ciao', 'fr', 'salut')
Это особенно касается ссылок. Чтобы использовать ссылочное значение, вы можете комбинировать сигилы вместе.
my @array = 1..5; # This is an array
my $reference_to_an_array = \@array; # A reference to an array is a singular value
push @array, 6; # push expects an array
push @$reference_to_an_array, 7; # the @ sigil means what's on the right is an array
# and what's on the right is $reference_to_an_array
# hence: first a @, then a $
Вот, возможно, менее запутанный способ подумать об этом. Как мы видели ранее, вы можете использовать фигурные скобки, чтобы обернуть то, что находится справа от сигилы. Поэтому вы можете думать о @{}
как о чем-то, что берет ссылку на массив и дает вам ссылочный массив.
# pop does not like array references
pop $reference_to_an_array; # ERROR in Perl 5.20+
# but if we use @{}, then...
pop @{ $reference_to_an_array }; # this works!
Как оказалось, @{}
фактически принимает выражение:
my $values = undef;
say pop @{ $values }; # ERROR: can't use undef as an array reference
say pop @{ $values // [5] } # undef // [5] gives [5], so this prints 5
... и тот же трюк работает и для других сигил.
# This is not an example of good Perl. It is merely a demonstration of this language feature
my $hashref = undef;
for my $key ( %{ $hashref // {} } ) {
"This doesn't crash";
}
... но если «аргумент» для сигилы прост, вы можете оставить фигурные скобки.
say $$scalar_reference;
say pop @$array_reference;
for keys (%$hash_reference) { ... };
Все может стать чрезмерно экстравагантным. Это работает, но, пожалуйста, Perl ответственно.
my %hash = (it => 'ciao', en => 'hi', fr => 'salut');
my $reference = \%hash;
my $reference_to_a_reference = \$reference;
my $italian = $hash{it}; # Direct access
my @greets = @$reference{'it', 'en'}; # Dereference, then access as array
my %subhash = %$$reference_to_a_reference{'en', 'fr'} # Dereference ×2 then access as hash
Для большинства нормальных применений вы можете просто использовать имена подпрограмм без сигилы. (Переменные без сигилы обычно называются «barewords»). &
Sigil полезен только в ограниченном числе случаев.
Составление ссылки на подпрограмму:
sub many_bars { 'bar' x $_[0] } my $reference = \&many_bars; say $reference->(3); # barbarbar
Вызов функции, игнорирующей ее прототип.
В сочетании с goto, как немного странный вызов функции, у которого текущий кадр вызова заменен вызывающим. Подумайте о вызове API linux
exec()
, но для функций.