【问题标题】:Confusion on syntax of of diamond operator in parsing and barewords菱形算子在解析和裸词中的语法混淆
【发布时间】:2022-01-31 00:40:33
【问题描述】:

我对 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 中使用裸词?有什么方法我应该避免在菱形运算符中使用裸词吗?

【问题讨论】:

  • 开启use strict;use warnings;。一个bareword是一个周围没有任何东西的词。菱形运算符意味着它不再是一个简单的词。
  • 参见perlop中关于I/O操作符的部分
  • 你对什么是bareword有一个奇怪的想法。该术语指的是一个不带引号的字符串,仅包含字母数字字符或下划线,在 Perl 语法中没有任何其他含义。因此,根据定义,$bare_word 不是 之一,$log_directory/* 也不是

标签: perl syntax


【解决方案1】:

您误认为菱形运算符&lt;&gt; 仅适用于裸字:

$ perl -E'say for <"/*">'
/bin
/boot
/dev
...

(实际上,bareword 只是一个没有符号的标识符,并且被 use strict 'subs'; 禁止,因此您的示例都没有真正的资格。)


这个:

@month_dirs = <$log_directory/*>;

之所以有效,是因为在 &lt;&gt; 内部完成了一定程度的双引号内插,并且像 $log_directory 这样的标量变量被内插。

相当于:

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

这个:

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

失败是因为$conf-&gt;log_directory() 中的&gt; 过早关闭了菱形运算符,从而混淆了解析器。

解析为:

<$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 或 typeglob 引用的简单标量变量,则将其解释为要通配的文件名模式,以及文件名列表或下一个文件名根据上下文返回列表中的。这种区别仅由句法基础决定。这意味着&lt;$x&gt; 始终是来自间接句柄的readline(),但&lt;$hash{key}&gt; 始终是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() . "/*" );

【讨论】:

    【解决方案2】:

    避免使用这种菱形运算符的主要原因之一是它有两个完全不相关的含义。您发现钻石的通常形式是

    $data = <$fh>;
    

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

    $data = readline( $fh );
    

    但是,您给出的原始表格是

    @month_dirs = <$log_directory/*>;
    

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

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

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

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

    【讨论】:

      【解决方案3】:

      bareword只能在括号里面,里面的语法是shell语法,更多的是perl一个

      # 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/*>;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-15
        • 1970-01-01
        • 2023-03-22
        • 2013-10-09
        相关资源
        最近更新 更多