检查sub是否返回undef

时间:2018-08-06 19:15:12

标签: arrays list perl undefined

人为的例子:

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?

3 个答案:

答案 0 :(得分:4)

列表上下文中的

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元素的列表几乎从来都不是您想要的。请参见How do I return nothing from a subroutine?,您通常只想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";
}

答案 1 :(得分:2)

与其他人一样,我建议使用element.all(by.css('#paragraphList table tbody tr'))或更明确的let allRows = element.all(by.css(`#paragraphList table tbody tr`)); //will have all the rows. allRows.then((rowsResolved) => { // now have all the rows PO.populateData(rowsResolved).then((allData) => {console.log(allData)}) // should be an Array od arrays, each array would be containing texts from all the cells. // Considering you have a Page Object and added the functions below in the Page Object. // Page Object is nothing but another class where we keep our utility methods }) // driving function populateData(rowsResolved) { let data = []; return this._populateRows(0, rowsResolved, data); } // calls itself recursively to loop over the rows private _populateRows(index, rowsResolved, data) { if (index >= rowsResolved.length) { let defer = protractor.promise.defer(); defer.fulfill(data); return defer.promise; // so that it is chainable even if I don't have any rows } let cells = element.all(by.css(`#paragraphList table tbody tr:nth-child(${index + 1}) td`)); cells.then((cellsResolved) => { let cellData = []; if (cellsResolved.length) { data.push(cellData); } this._populateCells(0, cellsResolved, cellData); return this._populateRows(index + 1, rowsResolved, data); }) } // calls itself recursively to loop over all the cells ofeach row. private _populateCells(index, cellsResolved, cellData) { if (index >= cellsResolved.length) { let defer = protractor.promise.defer(); defer.fulfill(cellData); return defer.promise; // so that it is chainable even if I don't have any cells(that would be an incorrect structure though, if a row exists then cells have to exist ) } cellsResolved[index].getText().then((cellValue) => { cellData.push(cellValue) }); return this._populateCells(index + 1, cellsResolved, cellData); } 。这将返回一个空列表。但是,由于该示例是人为设计的,因此我们无法确定空列表不是有效的返回值。如果这是有效的回报,或者合理地说是一天,那么您还有其他选择,IMO不太理想,但是可以更灵活。

一个很明显的方法是使用return,正如zdim所建议的那样,但是这种方法比较笨拙。实际上可能确实是您想要的-如果这种情况确实不应该发生,那么die就是完美的选择,因为如果不将失败包装在return ()中,它可能会导致程序中止。

另一种选择是让您的子返回数组引用而不是列表。然后,您可以直接返回die,您的呼叫者就可以很容易地检查到这一点:eval。该数组的其他用途仅需要进行解除引用,例如undef。当简单的my $result = my_sub(...);无法满足要求时,这可能是我的偏爱。值得一提的是,只有引用被传回,而不是整个列表。即使空列表无效但列表可能很大,也可以考虑这样做。

其他选项也很多,尽管这些选项可能是最简单的。例如,您可以返回一个哈希(或数组),其中一个条目指示成功/失败,另一个则指示该数组。您可以将成功/失败作为第一个元素返回(您想做的示例将是my ($res1, $res2, $res3) = @$result;,然后将第一个元素移开以查看它是否成功)。您可以将返回值嵌入封装了所有内容的对象中。在这些对象中,只有我会认真考虑的对象,但这在很大程度上取决于体系结构的其余部分,并且非常少见。

答案 2 :(得分:0)

子例程在您使用的列表上下文中返回标量列表,然后将其分配给变量。因此,如果您从中返回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 not“ false” (空列表),代码对其进行测试,因为它确实包含一个元素,即{{ 1}}。

对于这种“特殊”返回,在您认为特殊的情况下,可以使用不带任何参数的return或抛出一个die。有关上下文感知的返回,请参见wantarray