Perl: возвращаемое значение метода объекта не запускает оператор «if»

#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 это понятнее, другим легче понять и поддерживать, и не более неэффективно.