从函数返回perl中的+ {}或{}与返回ref或value之间的区别

Sah*_*han 8 perl

我刚刚开始与一个新的团队新工作.他们告诉我,我们在perl模块中返回ref而不是value.我还看到了return +{foo=>'bar'}; and return {foo=>'bar'};Whats的不同之处?是否返回ref或value?

ike*_*ami 21

+return +{foo=>'bar'}是完全无用的.


首先,一些背景.

Perl语言含糊不清.举个例子

sub f {
   {  }     # Is this a hash constructor or a block?
}
Run Code Online (Sandbox Code Playgroud)

{ }是块的有效语法("裸循环").
{ }是哈希构造函数的有效语法.
两者都被允许作为声明!

所以Perl必须猜测.Perl通常猜对了,但并不总是这样.你可以给它"提示".一元 - +可以用来做到这一点.一元+是一个完全透明的运营商; 它什么都不做.但是,必须后跟表达式(不是语句).{ }只有一种可能的含义作为表达.

+{ }   # Must be a hash constructor.
Run Code Online (Sandbox Code Playgroud)

同样,你可以欺骗Perl来猜测另一种方式.

{; }   # Perl looks ahead, and sees that this must be a block.
Run Code Online (Sandbox Code Playgroud)

这是Perl猜错的一个例子:

map { {} } 1..5   # ok. Creates 5 hashes and returns references to them.
map {}, 1..5      # XXX Perl guesses you were using "map BLOCK LIST".
map +{}, 1..5     # ok. Perl parses this as "map EXPR, LIST".
Run Code Online (Sandbox Code Playgroud)

至于问题中的代码,return必须跟一个表达式(如果有的话),所以只有一种可能的解释return { ... };,所以在+那里完全没用.

大多数人只在必要时才消除歧义.其他人可能会添加+它的含糊不清(即使Perl猜对了).但这是我第一次听说+在每个哈希构造函数前使用它.


Thi*_*Not 10

有什么不同?

那些是完全一样的,所以这+是无关紧要的.你可以通过使用B :: Deparse来看到这个:

$ perl -MO=Deparse -e'sub foo { return { foo => "bar" } }'
sub foo {
    return {'foo', 'bar'};
}
-e syntax OK

$ perl -MO=Deparse -e'sub foo { return +{ foo => "bar" } }'
sub foo {
    return {'foo', 'bar'};
}
-e syntax OK
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您都会返回对哈希的引用.


正如Hunter McMillen在评论中所说,在某些情况下,您需要使用一元运算+符来解决歧义.

例如,要区分匿名哈希和块中的块map:

$ perl -e'@a = map { $_ => "foo" }, 1..3'   # { ... } treated as a block
syntax error at -e line 1, near "},"
Execution of -e aborted due to compilation errors.

$ perl -e'@a = map +{ $_ => "foo" }, 1..3'  # { ... } treated as a hashref
Run Code Online (Sandbox Code Playgroud)

是否返回ref或value?

通过"返回一个值",我假设你的同事意味着这样的事情:

sub foo {
    my %bar = ( baz => 'qux' );
    return %bar;  # as opposed to \%bar
}

my %hash = foo();
Run Code Online (Sandbox Code Playgroud)

子例程只能返回一个标量列表,所以这大致相当于

my %hash = ('baz', 'qux');
Run Code Online (Sandbox Code Playgroud)

如果%bar包含许多项目,则复制此列表会变得昂贵,因此最好返回引用:

sub foo {
    my %bar = ( baz => 'qux' );
    return \%bar;
}

my $hashref = foo();
Run Code Online (Sandbox Code Playgroud)

  • 注意:Deparse是一个很好的参考,但它不是确定的.如果你想要一个明确的比较,你可以使用`diff -u <(perl -MO = Concise,-exec,foo -e'sub foo {return {foo =>"bar"}}'2>&1)<(perl -MO =简洁,-exec,foo -e'sub foo {return + {foo =>"bar"}}'2>&1)`. (2认同)