我有一个函数,它依赖于调用上下文,我想使用这个函数作为其他函数的参数。令人惊讶的是,我发现现在在列表上下文中调用了这个second
函数。我尝试使用+()
强制标量上下文,但它不能像我预期的那样工作。所以唯一的方法就是用scalar
隐式调用它。
use 5.010;
say first( 1, second( 'y' ) );
say first( 1, +( second( 'y' ) ) );
say first( 1, scalar second( 'y' ) );
sub first {
my $x = shift;
my $y = shift;
return "$x + $y";
}
sub second {
my $y = shift;
if ( wantarray ) {
qw/ array array /;
} else {
'scalar';
}
}
__END__
1 + array
1 + array
1 + scalar
函数的参数被视为列表,但它是否意味着该列表中的每个参数也都意味着列表上下文?如果是,那么为什么?
并且,使用scalar
有效,但我还有哪些方法可以在标量上下文中调用此函数(没有中间变量)?
答案 0 :(得分:7)
在列表上下文中评估函数参数是有意义的:
在Perl中,所有子例程都将列表映射到列表。
如果一个子获取列表,那么评估列表上下文中的所有参数是有意义的,这使得函数可组合。考虑map
:
map { ... } 1, 2, 3; # makes sense
map { ... } foo(); # can we "return 1, 2, 3" for the same effect?
如果在标量上下文中调用foo()
,当我们打算返回列表return 3
时,这相当于1, 2, 3
。使用列表上下文使我们能够在没有许多显式循环的情况下组成列表转换。 Schwartzian变换就是一个很好的例子:
my @sorted =
map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [make_key($_), $_] }
@input;
评估列表上下文中的参数有两种方法:
使用强制标量上下文的表达式,如scalar
或标量操作。
使用原型,例如($)
。这破坏了函数的可组合性,要求您的子例程预先声明,可能具有令人困惑的语义,并且远距离操作。因此应避免使用原型。
您的+(...)
没有强制标量上下文,因为一元加上没有强加上下文。它通常用于消除来自功能应用程序(例如用于优先级)的parens(例如用于优先级)。 map +($_ => 2*$_), 1, 2, 3
。
一元加号与二进制加号不同,后者是一个算术运算符,它在其操作数上强制使用标量上下文并将它们强制转换为数字。
答案 1 :(得分:4)
为什么函数参数会导致列表上下文?
子例程接受可变数量的标量作为参数。还有什么其他选择?
函数的参数被视为列表,但它是否意味着该列表中的每个参数也都意味着列表上下文?如果是,那么为什么?
是。因为您希望能够根据哈希和数组的内容构建列表。有一百万个理由说明这是有用的。
%h = (%h, ...); # Add to a hash
f( $x, @opts ); # Composing argument lists
etc
使用
scalar
有效,但我还有哪些方法可以在标量上下文中调用此函数(没有中间变量)?
有点儿。
say first( 1, "".second( 'y' ) ); # Side-effect: stringification
say first( 1, 0+.second( 'y' ) ); # Side-effect: numificatiion
say first( 1, !!second( 'y' ) ); # Side-effect: conversion to boolean
Subrountine原型也可以强制执行标量上下文,但由于这个原因,它们通常被认为是不好的。