我对 perl 很陌生,所以我确信我在这里的困惑仅仅是由于不理解 perl 语法以及它如何处理裸词。不过,我无法在网上找到我的问题的好答案。
我有我正在重构的代码,它曾经看起来像这样
@month_dirs = <$log_directory/*>;
我将 $log_directory 更改为加载配置文件(确切地说是 AppConfig)。现在我们输出 $conf 而不是导出 $log_directory ,它是一个 AppConfig 对象。要访问加载的变量,您通常会对变量名称进行方法调用,所以我尝试...
@month_dirs = <$conf->log_directory()."/*">
这失败了,因为我无法在需要 barword 的位置调用 $conf->log_directory 方法。只是在玩耍,我尝试了这个
$month_directory_command = $conf->log_directory()."/*";
@month_dirs = <$month_directory_command>;
这仍然默默地失败,没有任何迹象表明这是一个问题。我尝试直接在钻石中使用字符串但它失败了,显然只有裸词,而不是字符串,被钻石接受我对此感到惊讶,因为我根本不允许使用字符串,我认为大多数地方 Barewords 可以可以改为使用字符串,这仅仅是因为大多数代码实现了单独的逻辑来接受裸字与字符串,但不需要以这种方式实现?
我可以通过完全模仿原始语法来完成这项工作
$month_directory_command = $conf->log_directory();
@month_dirs = <$month_directory_command/*>;
但是,这对我来说很难看。我也很困惑为什么我能做到这一点,但我无法创建一个简单的词:
$bare_word = $conf->log_directory()/*
或者
$month_directory_command = $conf->log_directory();
$bare_word = $month_directory_command/*;
@month_dirs = <$bare_word>;
为什么有些变量对裸词有效,而对其他变量无效?为什么我可以使用缩放器变量,但如果它是从方法调用返回的则不能?
我尝试在裸字上查找 perl 语法,但没有太多运气来描述它们不是直接编写而是由变量组成的情况。
我希望有人可以帮助我更好地理解这里的裸词语法。什么定义了我何时可以将变量用作裸词的一部分以及是否可以将其保存为变量?
如果可以建议的话,我想找出一种更简洁的语法,以便在我的菱形运算符中使用 barword,但更重要的是,我想了解语法,以便我知道将来如何使用 barword。我保证我确实尝试过提前解决这个问题,但没有太多运气。
顺便说一句,似乎建议不要在 perl 中使用裸词?是否有某种方式我应该避免在钻石运算符中使用裸词?
最佳答案
您误认为钻石运算符 <>
仅适用于裸词:
$ perl -E'say for <"/*">'
/bin
/boot
/dev
...
(事实上,一个裸词只是一个没有符号的标识符,并且被 use strict 'subs';
禁止,所以你的例子都没有真正符合条件。)这:
@month_dirs = <$log_directory/*>;
之所以有效,是因为在 <>
内部完成了一定程度的双引号内插。 , 和标量变量,如 $log_directory
被插值。它相当于:
@month_dirs = glob("$log_directory/*");
这:
@month_dirs = <$conf->log_directory()."/*">
失败,因为 >
在 $conf->log_directory()
过早关闭菱形运算符,使解析器感到困惑。它被解析为:
<$conf->
(调用 glob
)然后log_directory()."/*">
这是一个语法错误。这:
$month_directory_command = $conf->log_directory()."/*";
@month_dirs = <$month_directory_command>;
失败是因为<$month_directory_command>
相当于readline($month_directory_command)
而不是glob("$month_directory_command")
来自 perldoc perlop
:If what the angle brackets contain is a simple scalar variable (for example,
$foo
), then that variable contains the name of the filehandle to input from, or its typeglob, or a reference to the same.[...]
If what's within the angle brackets is neither a filehandle nor a simple scalar variable containing a filehandle name, typeglob, or typeglob reference, it is interpreted as a filename pattern to be globbed, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined on syntactic grounds alone. That means
<$x>
is always areadline()
from an indirect handle, but<$hash{key}>
is always aglob()
.
因此,您正在尝试从尚未打开的文件句柄 (
$month_directory_command
) 中读取。使用
use warnings 'all';
打开警告会提醒你这一点:readline() on unopened filehandle at foo line 6.
这:
$bare_word = $conf->log_directory()/*;
失败,因为您试图将方法调用的结果与未加引号的字符串连接起来;要连接字符串,您必须将它们插入双引号字符串,或使用连接运算符。你可以这样做:
$bare_word = $conf->log_directory() . "/*";
@month_dirs = <"$bare_word">;
(尽管 $bare_word
根本不是一个裸词,它是一个标量变量。)注意:
@month_dirs = <$bare_word>;
(不带引号)将被解释为 readline
,而不是 glob
,如 perlop
中所述多于。不过,一般来说,使用
glob
可能不会那么困惑。运营商直接:@month_dirs = glob( $conf->log_directory() . "/*" );
关于perl - 菱形算子在解析和裸词中的语法混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34420975/