Thursday, February 25, 2010

Как сделать unbless в Perl

В Perl объекты - это обычные ссылки, в которых кроме прочего содержится информация о пакете (классе), к которому данный "объект" принадлежит. Для создания объекта служит функция bless:

bless {}, MyPackage;


Иногда бывает необходимо получить собственно ссылку, без информации о пакете. Такая необходимость может возникнуть, например, при использовании шаблонизатора или сериализации объекта в YAML или JSON. Например, оператор '.' в Template Toolkit всегда сначала пробует использовать строку справа как метод, затем как ключ хэша, etc.

Конечно, в таких случаях можно просто скопировать данные в новую структуру, но это было бы не эффективно, особенно при работе с большими структурами данных. Намного эффективней выполнить действие, обратное bless.

К сожалению, функции unbless в самом языке нет. Зато она есть в модуле Data::Structure::Util:

use Data::Structure::Util 'unbless';
use Scalar::Util 'refaddr';

my $x = bless {}, 'MyPackage';
printf "%s: %sn", refaddr $x, ref $x;
unbless $x;
printf "%s: %sn", refaddr $x, ref $x;



160126928: MyPackage
160126928: HASH


Как видим, адрес переменной не изменился. А вот "тип" ссылки изменился с MyPackage на HASH.

Friday, February 12, 2010

Perl: массивы и списки

my @a = ('a', 'b', 'c', 'd');
my $x;


Каким будет результат следующих, внешне немного похожих, выражений:

  • $x = @a;

  • $x = @a[0..3];

  • $x = ('a', 'b', 'c', 'd');

  • $x = () = ('a', 'b', 'c', 'd');

Wednesday, February 10, 2010

Perl: особенности цикла foreach

Цикл foreach в Perl всегда "локализует" переменную цикла, будь то глобальная переменная или переменная, объявленная с помощью my:
my $x = 1;
for $x (0..3) {}
print $x;  # 1, а не 3


Для сравнения сишный for:
my $x = 1;
for (; $x < 10; $x++) {}
print $x;  # 10, что логично


Еще одна особенность первого примера - отсутствие предупреждений при ре-декларации переменной цикла:

use warnings;

for my $x (0..3) {
my $x = "foo";
print $x;
}



Для сравнения:
use warnings;

{
my $x = 0;
my $x;
}
"my" variable $x masks earlier declaration in same scope