我刚刚开始在新的团队、新的地方工作。他们告诉我我们在 Perl 模块中返回 ref 而不是 value。我还看到类似
return +{foo=>'bar'}; and return {foo=>'bar'};
有什么区别?以及是否返回ref或value?
+
中的return +{foo=>'bar'}
完全没用。
首先,一些背景知识。
Perl 语言有歧义。举个例子吧
sub f {
{ } # Is this a hash constructor or a block?
}
{ }
是块的有效语法(“裸循环”)。{ }
是哈希构造函数的有效语法。所以 Perl 必须猜测。 Perl 通常会猜测正确,但并非总是如此。你可以给它“提示”。 Unary-
+
可以用来做到这一点。 Unary-+
是一个完全透明的运算符;它什么也不做。[1] 但是,它后面必须跟一个表达式(而不是语句)。 { }
作为表达式只有一种可能的含义。
+{ } # Must be a hash constructor.
同样,你可以欺骗 Perl 以另一种方式猜测。
{; } # Perl looks ahead, and sees that this must be a block.
这里有一个 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".
至于问题中的代码,
return
后面必须跟一个表达式(如果有的话),所以return { ... };
只有一种可能的解释,所以+
在那里完全没用。
大多数人只在必要时消除歧义。当它不明确时,其他人可能会添加
+
(即使 Perl 猜对了)。但这是我第一次听说使用 +
,但两者都不是。
+
甚至不强加标量上下文。相反,它将其上下文传播到其操作数上。有什么区别?
这些是完全相同的,所以
+
是无关的。您可以使用 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
在这两种情况下,您都会返回对哈希的引用。
正如 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
以及是否返回ref或value?
通过“返回一个值”,我认为你的同事的意思是这样的:
sub foo {
my %bar = ( baz => 'qux' );
return %bar; # as opposed to \%bar
}
my %hash = foo();
子例程只能返回标量列表,因此这大致相当于
my %hash = ('baz', 'qux');
如果
%bar
包含许多项目,复制此列表会变得昂贵,因此最好返回引用:
sub foo {
my %bar = ( baz => 'qux' );
return \%bar;
}
my $hashref = foo();