在perl解析和裸字中混淆dimond算子的语法

时间:2015-12-22 17:05:23

标签: perl syntax

我是perl的新手,所以我确定我在这里的困惑仅仅是因为不了解perl语法以及它如何处理裸露的单词。我没有在网上找到我的问题的好答案。

我有重构的代码,它看起来像这样

@month_dirs = <$log_directory/*>;

我更改了$ log_directory以加载配置文件(确切地说是AppConfig)。现在输出$ conf这是一个AppConfig对象而不是导出$ log_directory。要访问加载的变量,通常会对变量名称进行方法调用,所以我尝试了...

@month_dirs = <$conf->log_directory()."/*">

这失败了,因为我无法在预期使用bar字的位置调用$ conf-&gt; 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,如果可以建议的话,但更多的是我想了解语法,所以我知道如何在将来使用裸字。我保证我确实试过提前打算这个,但没有太多运气。

顺便说一句,似乎建议不要在perl中使用裸字?在某种程度上,我应该避免在钻石运算符中使用裸字吗?

3 个答案:

答案 0 :(得分:6)

您错误地认为钻石运算符<>仅适用于裸字:

$ 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

  

如果尖括号包含的是一个简单的标量变量(例如,$foo),则该变量包含要从中输入的文件句柄的名称,或其typeglob,或者对该变量的引用。 / p>      

[...]

     

如果尖括号内的内容既不是文件句柄也不是包含文件句柄名称,typeglob或typeglob引用的简单标量变量,则它被解释为要进行全局化的文件名模式,以及文件名列表或下一个文件名在列表中返回,具体取决于上下文。这种区别仅仅是出于句法原因而确定的。这意味着<$x>始终是来自间接句柄的readline(),但<$hash{key}>始终是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() . "/*" );

答案 1 :(得分:4)

避免这样的钻石经营者的主要原因之一是它有两个完全不相关的含义。你发现钻石的通常形式是

$data = <$fh>;

这就像一个读取功能;此函数的完整(非符号)名称为readline。这行来源相当于

$data = readline( $fh );

但是,您提供的原始表格是

@month_dirs = <$log_directory/*>;

这是一种完全不同的形式。这就像一个shell glob,通过扫描文件系统返回文件名匹配列表。使用glob函数更好地写出此表单:

@month_dirs = glob( "$log_directory/*" );

另请注意,这是一个普通函数,只需要一个普通的字符串参数。通过这种方式,您可以将它与任何提供的示例一起使用,例如:

@month_dirs = glob( $conf->log_directory()."/*" );

答案 2 :(得分:0)

bareword只能在括号内&lt;&gt;里面,语法里面是shell语法,更多是perl one

# wrong -     
$bare_word = $month_directory_command/*;
# right - star is allowed because it is inside the quote single or double
$bare_word = "$month_directory_command/*";

# star is allowed simply because it is inside the bracket
@month_dirs = <$month_directory_command/*>;