perl - 菱形算子在解析和裸词中的语法混淆

标签 perl syntax

我对 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 a readline() from an indirect handle, but <$hash{key}> is always a glob().


因此,您正在尝试从尚未打开的文件句柄 ( $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/

相关文章:

python - 为什么我会收到 TypeError : unsupported operand type(s) for +

regex - 检查是否由 `perl -i -pe` 完成任何替换

regex - 为什么命令行中 s/g 的以下变体是错误的?

c# - 简化正则表达式或模式

shell - `if (( ... )) then` 中缺少分号并且没有语法错误?

iTerm 2 中的 Git 语法高亮显示

regex - 如何使用 Perl 匹配 Unicode 文本中的俄语单词?

perl - 该Perl代码如何工作?

generics - 类型参数与 std::ops::BitXor 输出关联类型之间的类型不匹配

c - 如何根据成员名称在 C 中初始化结构体