Надуманный пример:
use strict;
use warnings;
my $myval = 'a';
my @result = my_sub($myval);
if (@result) {
print "DEFINED\n";
}
my ($res1, $res2, $res3) = @result;
print "res1=$res1, res2=$res2, res3=$res3\n";
sub my_sub {
my $myval = shift;
if ($myval eq 'a') {
return undef;
}
return ("a","b","c");
}
Как мне проверить, вернул ли sub undef?
или же
Как проверить, не вернул ли sub undef?
См. Также Замена устаревшего слова «defined (@array)» в тернарной операции и Определение (@array) устарело.
Используйте только return;. Он автоматически вернет undef в скалярном контексте и () в контексте списка. Добавление аргумента к возврату может вызвать труднодоступные ошибки.



return undef в контексте списка возвращает список из одного элемента, которым является undef.
@result = my_sub($myval);
if (@result == 1 && !defined($result[0])) {
warn "my_sub() returned undef";
} else {
print "my_sub() returned data\n";
}
Тем не менее, список с одним элементом undef почти никогда не является тем, что вам нужно. См. Как мне ничего не вернуть из подпрограммы?. Обычно вы просто хотите использовать return без аргументов. В скалярном контексте это возвращает undef, а в контексте списка - пустой список.
sub my_other_sub {
my $myval = shift;
if ($myval eq 'a') {
return;
}
return ("a","b","c");
}
...
@result = my_other_sub($arg1);
$result = my_other_sub($arg2);
if (@result == 0) { # or: if (!@result) ... or: unless (@result) ...
warn "my_other_sub(arg1) did not return any data";
} else {
print "my_other_sub(arg1) returned data\n";
}
if (!defined($result)) {
warn "my_other_sub(arg2) did not return any data";
} else {
print "my_other_sub(arg2) returned data\n";
}
Подпрограмма возвращает список скаляров в контексте списка, который вы используете, а затем назначаете переменным. Итак, если вы вернете из него undef, переменные $res будут undef - сначала назначены undef, а другие не назначены (в то время как массив @result будет иметь один элемент, undef)
perl -Mstrict -wE'
my $val = shift;
sub t { return undef if shift eq "bad"; return qw(a b) };
my ($v1, $v2) = t($val);
if (not defined $v1 and not defined $v2) { say "undef" }
else { say "$v1, $v2" }
' bad
Первый shift берет значение из @ARGV, поэтому измените ввод «Плохо», чтобы увидеть другие случаи. Это можно было бы написать более компактно и яснее, если бы мы знали, как это использовать.
Я понимаю, что это тестовый пример, но он все еще слишком запутан и допускает сложные крайние случаи; например, ваш первый случай не будет работать, поскольку @result - это не "ложь" (пустой список), на что проверяет код, поскольку он имеет один элемент, которым является undef.
Для таких «специальных» возвратов либо используйте возвращаться без аргументов, либо бросьте умри в ситуациях, которые вы считаете исключительными. Для контекстно-зависимых возвратов см. хочу.
Я бы рекомендовал, как и другие, использовать return или более явный return (). Это возвращает пустой список. Однако, поскольку пример надуманный, мы не можем быть уверены, что пустой список не является допустимым возвратом в противном случае. Если это действительный возврат или это может быть разумно в один прекрасный день, тогда у вас есть другие варианты, которые, IMO, менее идеальны, но могут быть более гибкими.
Очевидный вариант - использовать die, как предлагал zdim, но это может быть относительно тяжеловесно. На самом деле это может быть именно то, что вы хотите - если эта ситуация действительно не должна произойти, die идеально подходит, так как это может привести к прерыванию вашей программы, если вы не заключите сбой в eval.
Другой альтернативой является возвращение вашей подпрограммы ссылки на массив вместо списка. И затем вы можете напрямую вернуть undef, ваш вызывающий сможет легко это проверить: my $result = my_sub(...);. Для других применений этого массива просто потребуется разыменование, например, my ($res1, $res2, $res3) = @$result;. Это, наверное, я предпочитаю, когда простого return () недостаточно. Бонус в том, что обратно передается только ссылка, а не весь список. Подумайте о том, чтобы сделать это, даже если пустой список недействителен, но список может быть очень большим.
Есть и другие варианты, хотя они, вероятно, самые простые. Вы можете, например, вернуть хэш (или массив), в котором одна запись указывает успех / неудачу, а другая - массив. Вы можете вернуть успех / неудачу в качестве первого элемента (ваш надуманный пример будет return (1, "a", "b", "c"), и вы должны сдвинуть этот первый элемент, чтобы увидеть, был ли он успешным или нет). Вы можете встроить свой доход в объект, который все это инкапсулирует. Из них я бы серьезно рассмотрел только один объект, но он будет сильно зависеть от остальной архитектуры и будет очень редким.
Используйте
return ()или простоreturnвместоreturn undef.