@a = (2,3,4,5); my $a = {a=>"q", b=>@a, c=>2}; print $a->{c}; Ответ: undef
Пояснение: хеш представляет собой список с пар(ключ/значение). значение(как и ключ) всегда представляет собой скаляр. Оператор => - по своей сути, это синоним оператору ",", только он еще берет левый аргумент в двойные кавычки.
Эта запись {a=>"q", b=>@a, c=>2} на самом деле
равна {"a", "q", "b" , @a, "c", 2},
либо {"a", "q", "b" , 2, 3, 4, 5, "c", 2}
либо {a => "q", b => 2, 3 => 4, 5 => "c", 2 } и можем видеть, что ключа "c" просто нет в хеше.
Если мы хотим, обращаться по ключу к массиву, то мы должны указать в качестве значения ссылку на масив, а не масив как список.
my $a = {a=>"q", b=>\@a, c=>2}.
среда, 31 марта 2010 г.
понедельник, 29 марта 2010 г.
Тест на понимание Perl: идея и вопрос 1
Идея
Решил написать серию постов с вопросами на понимание Perl. То есть каждый пост - отдельный вопрос. Каждый такой пост будет содержать: вопрос, ответ, объяснение ответа.
Вопросы не будут содержать каких-либо редко используемых функций. Главное здесь проверить не знание функций, а понимание поведения Perl-кода. Возможно многим они покажутся очевидными, но это говорит о том, что вы понимаете Perl ;)
Решил написать серию постов с вопросами на понимание Perl. То есть каждый пост - отдельный вопрос. Каждый такой пост будет содержать: вопрос, ответ, объяснение ответа.
Вопросы не будут содержать каких-либо редко используемых функций. Главное здесь проверить не знание функций, а понимание поведения Perl-кода. Возможно многим они покажутся очевидными, но это говорит о том, что вы понимаете Perl ;)
Когда вопросов насобирается 20 штук - соберу все в один тест.
Вопрос 1
@a = 0; print 10 if @a
Ответ: 10
Пояснение: Все логические операции работают в скалярном контексте. В данном случае запись эквивалентна print 10 if scalar(@a)
суббота, 27 марта 2010 г.
Комментарии на русском языке(utf-8) в perl коде - ЗЛО || ДОБРО ?
Какие могут быть проблемы? Я пока вижу следующие:
Проблема 1. Необходимо всем перенастроить редакторы кода. У нас в компании нет ограничения на использование редакторов кода - используются Vim, Eclipse, Geany, Far... С Far есть явная проблема, которая заключается в необходимости постоянного переключении редактора в режим юникода для просмотра комментария. С vim тоже есть проблема - при переключении раскладки на русский язык не работают хоткеи(конечно можно помучится и настроить их), что реальное неудобно. Я думаю, что программисты, которые пишут в vim просто будут писать комменты на английском. По поводу Geany я ничего сказать не могу, с Eclipse должно быть все хорошо.
Проблема 2. Перенастроить продакшен сервера, чтобы на них корректно показывались кириллические комменты - доставить шрифты и так далее.
Проблема 3. Post commit SVN хук, который отправляет diff на почту разработчикам не дружит с не ASCII символами. Допускаю(но не утверждаю :) ), что возможно будут проблемы с svn diff и слиянием веток.
Проблема 4.. Непоследовательность. Разработка ведется на Perl и на Javascript, но для Javascript нельзя точно нельзя разрешать кириллицу, поскольку это может вылезти серьезными багами(проверено на собственном опыте). Только часть(10-30%) разработчиков будет использовать кириллицу.
Проблема 5(потенциальная).. Сразу ограничиваем поддержку кода, только русскоговорящим населением.
Возможно имеет смысл создавать отдельные ru/SomeModule.pod файлы для кириллической документации.
Возможно есть еще какие-то проблемы и подводные камни? Буду рад увидеть в комментариях мнения по этому поводу. Возможно кто-то уже использует кириллицу и готов поделится опытом?
ЗЫ: я не люблю читать модули в CPAN с документацией на японском ;)
Проблема 1. Необходимо всем перенастроить редакторы кода. У нас в компании нет ограничения на использование редакторов кода - используются Vim, Eclipse, Geany, Far... С Far есть явная проблема, которая заключается в необходимости постоянного переключении редактора в режим юникода для просмотра комментария. С vim тоже есть проблема - при переключении раскладки на русский язык не работают хоткеи(конечно можно помучится и настроить их), что реальное неудобно. Я думаю, что программисты, которые пишут в vim просто будут писать комменты на английском. По поводу Geany я ничего сказать не могу, с Eclipse должно быть все хорошо.
Проблема 2. Перенастроить продакшен сервера, чтобы на них корректно показывались кириллические комменты - доставить шрифты и так далее.
Проблема 3. Post commit SVN хук, который отправляет diff на почту разработчикам не дружит с не ASCII символами. Допускаю(но не утверждаю :) ), что возможно будут проблемы с svn diff и слиянием веток.
Проблема 4.. Непоследовательность. Разработка ведется на Perl и на Javascript, но для Javascript нельзя точно нельзя разрешать кириллицу, поскольку это может вылезти серьезными багами(проверено на собственном опыте). Только часть(10-30%) разработчиков будет использовать кириллицу.
Проблема 5(потенциальная).. Сразу ограничиваем поддержку кода, только русскоговорящим населением.
Возможно имеет смысл создавать отдельные ru/SomeModule.pod файлы для кириллической документации.
Возможно есть еще какие-то проблемы и подводные камни? Буду рад увидеть в комментариях мнения по этому поводу. Возможно кто-то уже использует кириллицу и готов поделится опытом?
ЗЫ: я не люблю читать модули в CPAN с документацией на японском ;)
воскресенье, 21 марта 2010 г.
Экономия памяти: прием по ссылке
Не для кого не секрет, что Perl любит кушать память и при написании кода нужно обращать внимание на всякие мелочи, если вы работаете с большими объемами данных. Проблема заключается в том, что когда Perl съедает память, он ее не возвращает системе, а оставляет себе для повторного использования. Для долгоживущих процессов это иногда создает проблемы.
Допустим у нас есть огромный блок данных - $data;
и функция для записи данных в файл $file - set_file_content;
sub set_file_content {
my ($file, $data) = @_;
....
print FILE $data;
}
Вариант 1
set_file_content("$file", "$data") - самый нерациональный вариант вызова. Параметры заключены в двойные кавычки и Perl создаст в памяти еще одну копию строки для передачи в функцию.
Вариант 2
set_file_content($file, $data) - хороший вариант вызова, но тут уже проблема возникает в самой функции set_file_content - она внутри когда принимает параметры, копирует их в локальные переменные.
Вариант 3
Следовательно нужно избежать копирования данных внутри функции set_file_content и многие решат передавать и принимать данные по ссылке
используя токой вот вызов: set_file_content($file, \$data)
и такую реализацию функции:
sub set_file_content {
my ($file, $data_ref) = @_;
....
print FILE $$data_ref;
}
По использованию памяти - это отличный вариант, но есть другие недостатки:
1. Первый параметр передается обычным способом, второй по ссылке
2. Если код уже написан, то необходимо изменить везде код вызова функции
3. Самый существенный для меня недостаток - когда я передаю параметр по ссылке, я всегда задумываюсь, а не проделает ли функция каких либо операций с $data внутри и можно будет ли использовать переменную $data после вызова функции.
Вариант 4 (Сабж)
Так вот собственно перейдем к сабжу: прием по ссылке
Функцию set_file_content реализовываем следующим образом:
sub set_file_content {
my ($file, $data_ref) = ($_[0], \$_[1]);
....
print FILE $$data_ref;
}
Вызов мы используем обычный - set_file_content($file, $data);
В результате мы получаем полностью аналогичное потребление памяти как и с вариантом передачи по ссылке, но лишенный всех недостатков.
Почему это работает?
В перле есть понятие ссылки, а есть понятие алиаса(второго имени). Так вот, в массиве @_ содержатся алиасы на переданные параметры и модифицируя элементы @_, мы модифицируем внешние переменные.
Алиасы также используются в map, grep, foreach
Например:
foreach my $var (@array) {
$var = 1;
}
мы присвоим "1" каждому элементу массива @array
ЗЫ:
Когда использовать прием по ссылке, а когда передачу по ссылке? я придерживаюсь следующего правила:
some_function(\$data); - функция изменяет $data внутри
some_function($data); - функция не изменяет $data внутри
Допустим у нас есть огромный блок данных - $data;
и функция для записи данных в файл $file - set_file_content;
sub set_file_content {
my ($file, $data) = @_;
....
print FILE $data;
}
Вариант 1
set_file_content("$file", "$data") - самый нерациональный вариант вызова. Параметры заключены в двойные кавычки и Perl создаст в памяти еще одну копию строки для передачи в функцию.
Вариант 2
set_file_content($file, $data) - хороший вариант вызова, но тут уже проблема возникает в самой функции set_file_content - она внутри когда принимает параметры, копирует их в локальные переменные.
Вариант 3
Следовательно нужно избежать копирования данных внутри функции set_file_content и многие решат передавать и принимать данные по ссылке
используя токой вот вызов: set_file_content($file, \$data)
и такую реализацию функции:
sub set_file_content {
my ($file, $data_ref) = @_;
....
print FILE $$data_ref;
}
По использованию памяти - это отличный вариант, но есть другие недостатки:
1. Первый параметр передается обычным способом, второй по ссылке
2. Если код уже написан, то необходимо изменить везде код вызова функции
3. Самый существенный для меня недостаток - когда я передаю параметр по ссылке, я всегда задумываюсь, а не проделает ли функция каких либо операций с $data внутри и можно будет ли использовать переменную $data после вызова функции.
Вариант 4 (Сабж)
Так вот собственно перейдем к сабжу: прием по ссылке
Функцию set_file_content реализовываем следующим образом:
sub set_file_content {
my ($file, $data_ref) = ($_[0], \$_[1]);
....
print FILE $$data_ref;
}
Вызов мы используем обычный - set_file_content($file, $data);
В результате мы получаем полностью аналогичное потребление памяти как и с вариантом передачи по ссылке, но лишенный всех недостатков.
Почему это работает?
В перле есть понятие ссылки, а есть понятие алиаса(второго имени). Так вот, в массиве @_ содержатся алиасы на переданные параметры и модифицируя элементы @_, мы модифицируем внешние переменные.
Алиасы также используются в map, grep, foreach
Например:
foreach my $var (@array) {
$var = 1;
}
мы присвоим "1" каждому элементу массива @array
ЗЫ:
Когда использовать прием по ссылке, а когда передачу по ссылке? я придерживаюсь следующего правила:
some_function(\$data); - функция изменяет $data внутри
some_function($data); - функция не изменяет $data внутри
суббота, 20 марта 2010 г.
Разрешено анонимное комментирование :)
Теперь можно оставлять комментарии анонимно, необходимо только пройти проверку каптчей.
четверг, 18 марта 2010 г.
Никогда не пишите так m/$var/ :)
Не многие в курсе, но такая запись m/$var/ чревата сложно находимыми багами. Сразу оговорюсь, что это актуально если $var может быть пустой.
Пример 1
my $a = "text";
my $b = "text2";
print 1 if $b =~ /text2/;
print 2 if $a =~ //;
# В результате будет напечатано 1;
Пример 1
my $a = "text";
my $b = "text2";
print 1 if $b =~ /text2/;
print 2 if $a =~ //;
# В результате будет напечатано 1;
Пример 2
my $a = "text";
my $b = "text2";
print 1 if $b =~ /text3/;
print 2 if $a =~ //;
# В результате будет напечатано 2;
Perl вместо пустого регекспа всегда вставляет предыдущий успешно совпавший регексп. Все это описано в perldoc perlre :).
Бойтесь пустых регекспов и пишите, например так - m/(?:$var)/
вторник, 16 марта 2010 г.
Обновил Debug::LTrace до 0.02
* Обновилась документации и тесты.
* Теперь модуль без проблем инсталлируется под 5.8.x
ЗЫ: Как приятно смотреть на все эти зелененькие "PASS" в CPAN Testers Report :))
* Теперь модуль без проблем инсталлируется под 5.8.x
ЗЫ: Как приятно смотреть на все эти зелененькие "PASS" в CPAN Testers Report :))
воскресенье, 14 марта 2010 г.
Не только одними feature5.10... :)
Выложил свой модуль на CPAN и тут начались проблемы - CPAN Testers показывает, что во всех версиях перла ниже 5.10 тесты проваливаются, начал разбираться и вот:
в 5.10.x
print qr{\Q\_\E} #выведет:(?-xism:\\_)
print "\Q\_\E" #выведет:_
print "\Q\_\E" #выведет:_
в 5.8.x
print qr{\Q\_\E} #выведет:
(?-xism:_)
print "\Q\_\E" #выведет:
_
Занятно, однако ...
четверг, 11 марта 2010 г.
koorchik's Perl blog переехал с koorchik.name на koorchik.blogspot.com
Блог изначально создавался как просто страница с советами по Perl ("Perl Tips"), но в результате вырос и потребовался новый функционал, появились желающие прокомментировать посты...
Теперь koorchik's Perl blog можно найти по адресу http://koorchik.blogspot.com/ и все желающие могут оставлять комментарии. Если у кого-то возникало желание прокомментировать старый пост, то теперь можно это сделать, поскольку весь контент был полностью перенесен.
Теперь koorchik's Perl blog можно найти по адресу http://koorchik.blogspot.com/ и все желающие могут оставлять комментарии. Если у кого-то возникало желание прокомментировать старый пост, то теперь можно это сделать, поскольку весь контент был полностью перенесен.
Как добавить свою аватарку на CPAN
Залил свой модуль Debug::LTrace на CPAN и смотрю у меня дефолтовая аватарка.
Начал перерывать все пункты в меню моего аккаунта на PAUSE сервере в поисках формы аплоада аватарок и все тщетно. Через 15 минут меня совсем перестал удивлять тот факт, что так мало автором на CPAN имеют свои аватарки :)).
Так вот. Решил я посмотреть в html коде откуда подгружается аватарка на CPAN и... возможно это для меня только было новоcтью :)... но это gravatar.com.
В общем решение следующее: если у меня в PAUSE юзер называется koorchik, то просто регистрирую на gravatar.com аккаунт по емейлу koorchik@cpan.org и добавляю туда свою аватарку. И все! После этого CPAN сам подхватит ее.
Начал перерывать все пункты в меню моего аккаунта на PAUSE сервере в поисках формы аплоада аватарок и все тщетно. Через 15 минут меня совсем перестал удивлять тот факт, что так мало автором на CPAN имеют свои аватарки :)).
Так вот. Решил я посмотреть в html коде откуда подгружается аватарка на CPAN и... возможно это для меня только было новоcтью :)... но это gravatar.com.
В общем решение следующее: если у меня в PAUSE юзер называется koorchik, то просто регистрирую на gravatar.com аккаунт по емейлу koorchik@cpan.org и добавляю туда свою аватарку. И все! После этого CPAN сам подхватит ее.
среда, 10 марта 2010 г.
Debug::LTrace - мой дебют на CPAN
Debug::LTrace отслеживает вызов и возврат функций. Использование Debug::LTrace не требует никаких дополнительных изменений в коде. Информации о вызовах выводится через стандартный warn.
На CPAN есть и другие модули такие, как Devel::TraceCalls и Debug::Trace, но Devel::TraceCalls неудобный в использовании(хотя очень мощный), Debug::Trace - удобный и простой, но не хватает функционала.
Debug::LTrace за основу взял удобное API Debug::Trace, но дополнительно поддерживает:
На CPAN есть и другие модули такие, как Devel::TraceCalls и Debug::Trace, но Devel::TraceCalls неудобный в использовании(хотя очень мощный), Debug::Trace - удобный и простой, но не хватает функционала.
Debug::LTrace за основу взял удобное API Debug::Trace, но дополнительно поддерживает:
- Лексически ограниченный трейсинг(трейсит пока существует объект-трейсер)
- Стандартная функция caller отрабатывает нормально
- Трейсинг целых модулей (используя '*' для обозначения всех функций в модуле)
- Улучшенный вывод информации (дерево вложеностей)
- Больше отладочной информации (время выполнения, контекст вызова...)
Пример вывода:
TRACE C: /-FOO::out_outer() called at example.pl line 15 package FOO
TRACE C: | /-FOO::outer(2,{'aaa' => {'yyy' => 'ARRAY(0x7fe610)','qqq' => 'www'}}) called at example.pl line 49 sub FOO::out_outer
TRACE C: | | /-FOO::inner(3) called at example.pl line 32 sub FOO::outer
TRACE C: | | | /-FOO::Dumper(3) called at example.pl line 39 sub FOO::inner
TRACE R: | | | \_FOO::Dumper(3) [VOID] in 3.5e-05 sec
TRACE C: | | | /-FOO::inner2(3) called at example.pl line 40 sub FOO::inner
TRACE R: | | | \_FOO::inner2(3) [VOID] in 1.4e-05 sec
TRACE R: | | \_FOO::inner(3) [VOID] in 0.000213 sec
TRACE C: | | /-FOO::inner2(4) called at example.pl line 33 sub FOO::outer
TRACE R: | | \_FOO::inner2(4) [VOID] in 1.5e-05 sec
TRACE R: | \_FOO::outer(2,{'aaa' => {'yyy' => 'ARRAY(0x7fe610)','qqq' => 'www'}}) [VOID] in 0.000417 sec
TRACE C: | /-FOO::inner(111) called at example.pl line 50 sub FOO::out_outer
TRACE C: | | /-FOO::Dumper(111) called at example.pl line 39 sub FOO::inner
TRACE R: | | \_FOO::Dumper(111) [VOID] in 3.5e-05 sec
TRACE C: | | /-FOO::inner2(111) called at example.pl line 40 sub FOO::inner
TRACE R: | | \_FOO::inner2(111) returned: (112) in 4.4e-05 sec
TRACE R: | \_FOO::inner(111) returned: (112) in 0.000276 sec
TRACE R: \_FOO::out_outer() [VOID] in 0.00088 sec
TRACE C: /-FOO::recurse(1) called at example.pl line 25 package FOO
TRACE C: | /-FOO::recurse(2) called at example.pl line 58 sub FOO::recurse
TRACE C: | | /-FOO::recurse(3) called at example.pl line 58 sub FOO::recurse
TRACE C: | | | /-FOO::recurse(4) called at example.pl line 58 sub FOO::recurse
TRACE C: | | | | /-FOO::recurse(5) called at example.pl line 58 sub FOO::recurse
TRACE R: | | | | \_FOO::recurse(5) returned: (6) in 4.8e-05 sec
TRACE R: | | | \_FOO::recurse(4) returned: (6) in 0.000177 sec
TRACE R: | | \_FOO::recurse(3) returned: (6) in 0.00032 sec
TRACE R: | \_FOO::recurse(2) returned: (6) in 0.00044 sec
TRACE R: \_FOO::recurse(1) returned: (6) in 0.000562 sec
TRACE C: /-BAR::Dumper([1]) called at example.pl line 70 package BAR
TRACE R: \_BAR::Dumper([1]) [VOID] in 3.8e-05 sec
Подписаться на:
Сообщения (Atom)