#perl #oop
#perl #ооп
Вопрос:
Я пытаюсь отладить свою программу и хочу отправлять уведомления наблюдателю, если нужно получить какие-либо уведомления.
У меня есть метод Notify
, который возвращает список файлов, за которыми наблюдатель хочет следить. Моя debug
процедура предназначена только для того, чтобы помочь мне отладить мою программу.
Это работает. Я вижу, что вторая debug
процедура распечатывает значение:
foreach my $watcher ($watch->Watcher) {
debug qq(Sending out notifcations for ) . $watcher->User, 2;
my @foo = $watcher->Notify;
if (@foo) {
debug qq(Change list to notify on: ) . join (", " => $watcher->Notify), 3;
$watch->SendEmail($watcher);
}
}
Однако это не удается:
foreach my $watcher ($watch->Watcher) {
debug qq(Sending out notifcations for ) . $watcher->User, 2;
if ($watcher->Notify) {
debug qq(Change list to notify on: ) . join (", " => $watcher->Notify), 3;
$watch->SendEmail($watcher);
}
}
Разница между первым и вторым: в первом я возвращаюсь $watcher->Notify
к массиву @foo
и продолжаю тестирование @foo
. Во втором я проверяю возвращаемое значение $watcher->Notify
.
Подпрограмма уведомления выглядит следующим образом:
sub Notify {
my $self = shift;
my $change = shift;
$self->{CHANGE} = [] if not exists $self->{CHANGE};
if (defined $change) {
push @{$self->{CHANGE}}, $change;
}
return sort @{$self->{CHANGE}};
}
Подождите секунду…
Хорошо, когда я набирал этот вопрос, я понял, что когда я говорю if ($watcher->Notify)
, я возвращаюсь в скалярный контекст, а когда я говорю @foo = $watcher->Notify
, я возвращаюсь в контекст списка. Дальнейшее тестирование с помощью этого:
foreach my $watcher ($watch->Watcher) {
debug qq(Sending out notifcations for ) . $watcher->User, 2;
my $foo = $watcher->Notify; #Now a SCALAR and not a LIST
if ($foo) {
debug qq(Change list to notify on: ) . join (", " => $watcher->Notify), 3;
$watch->SendEmail($watcher);
}
}
Показал, что $foo
это значение равно нулю. Меняю свой метод на:
sub Notify {
my $self = shift;
my $change = shift;
$self->{CHANGE} = [] if not exists $self->{CHANGE};
if (defined $change) {
push @{$self->{CHANGE}}, $change;
}
if (wantarray) {
return sort @{$self->{CHANGE}};
}
else {
return scalar @{$self->{CHANGE}};
}
}
Теперь работает. (Теперь метод проверяет, нужен ли мне массив, и если я этого не делаю, он возвращает явный скаляр).
Вопрос в том, почему.
Я подумал, что если я верну массив в скалярный контекст, Perl должен либо автоматически выполнить scalar
для меня (и вернуть количество элементов в массиве), либо, по крайней мере, объединить все элементы в массиве с $"
помощью разделителя. (Я предположил первое, но последнее также сработало бы).
Например:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say switch);
use Data::Dumper;
my @foo = qw(this that the other);
my $bar = @foo;
say "Bar = $bar @foo = @foo";
выводит:
Bar = 4 @foo = this that the other
Где я ошибся? (Я имею в виду, помимо продажи всех моих акций Apple, когда цена поднялась до 40 долларов за акцию).
Ответ №1:
Вы не возвращали массив. Вы возвращали результат sort
вызова в скалярном контексте. Согласно документам:
В скалярном контексте поведение
sort()
не определено.
Это означает, что он может делать все, что захочет, включая возврат undef
.
Комментарии:
1. @MisterEd, согласно временным меткам, это было 50 секунд 😉 Но спасибо.
2. @MisterEd: потому что я вернул a
sort @array
, а не только@array
. Черт возьми. Недавно я перестал использовать проверку возврата сwantarray
помощью, потому что мне сказали, что в этом нет необходимости, и я думаю, что это не так, пока это не так.
Ответ №2:
Потому что вы возвращали результат sort
в скалярном контексте:
Из http://perldoc.perl.org/functions/sort.html:
В контексте списка это сортирует СПИСОК и возвращает отсортированное значение списка. В скалярном контексте поведение sort() не определено.
РЕДАКТИРОВАТЬ: если вы не хотите использовать wantarray
, вы можете изменить:
return sort @{$self->{CHANGE}};
Для:
return @{ [sort @{$self->{CHANGE}}] };
Комментарии:
1. Извините
cjm
, что опередил вас на несколько секунд. В любом случае спасибо. Да, я понимаю@{[...]}
, что я тоже могу это сделать, но для меняwantarray
это понятнее, другим легче понять и поддерживать, и не более неэффективно.