在使用其他人的Perl API时,避免使用$ _是一种约定吗?

Rob*_*lls 9 api perl calling-convention

当我将其他人的API与默认变量$ _结合使用时,我才被抓住了

foreach (@rps_server_details) {
    @server_data = ();
    @server_data = split(/,/);
    @$esp_hosts = ();
    $filters{server_name} = $server_data[0];
    print "--->$_<--\n";
    $esp_hosts = $esp->get_hosts(fields => $fields, %filters) || die "$@";
    print "--->$_<--\n";
Run Code Online (Sandbox Code Playgroud)

这个输出是:

--->igrid8873.someone.com,app_10<--
Use of uninitialized value in concatenation (.) or string at ./rps_inv_lookup.pl line 120.
---><--
Run Code Online (Sandbox Code Playgroud)

指定我自己的循环变量而不是依赖$ _修复问题.

通过将$ _与其他人编写的API结合使用,我是不是很天真?或者这是API模块中的错误?

Pee*_*ger 9

这是API中的一个错误.如果$_在函数中使用,则添加一个很重要

local($_);
Run Code Online (Sandbox Code Playgroud)

在函数内部,以避免破坏调用者$_,或以其他方式避免$_在库函数中使用.

如果你可以将yoursel限制为Perl版本> 5.9.1那么你也可以制作$ _ lexical,这比local使用它更容易理解

my $_;
Run Code Online (Sandbox Code Playgroud)

但这将在早期版本的Perl上破解.

来自man perlvar:

作为$_一个全局变量,这可能会在某些情况下导致不必要的副作用.从perl 5.9.1开始,你现在可以$_通过在文件中或在带有"my"的块中声明它来使用词法版本.此外,声明" our $_"恢复$_ 当前范围内的全局.


DVK*_*DVK 6

我会说是:

  1. 违反您的最佳做法(始终使用尽可能本地的可变范围,并避免$_因您遇到的问题而使用)

  2. 加上由于同样违反最佳做法而导致的API中的错误,以及没有将perldoc perlvarlocal $_禁止的特殊变量本地化.

除了perldoc之外,API违反了Perl最佳实践(如Conway的书中规则):

第5.6节.本地化标点符号变量

如果您被迫修改标点符号变量,请将其本地化.

前面"本地化"中描述的问题也可能在您被迫更改标点符号变量中的值时出现(通常在I/O操作中).所有标点变量都是全局范围的.它们提供了对完全内容的明确控制大多数其他语言中的隐式行为:输出缓冲,输入行编号,输入和输出行结束,数组索引等等.

在没有首先对其进行本地化的情况下更改标点符号变量通常是一个严重的错误.未本地化的分配可能会改变系统中完全不相关的部分中的代码行为,即使是在您自己编写但仅仅使用的模块中也是如此.

使用local是临时更改全局变量值的最干净,最稳健的方法.它应该始终应用在尽可能小的范围内,以便最小化变量可能控制的任何"环境行为"的影响:

这里也是完整的perldoc perlvar文档 - 在网页中搜索"nasty_break"这个词(我找不到直接的页面内链接,但它接近页面的开头)

修改本文档中描述的大多数特殊变量的默认值时应该非常小心.在大多数情况下,您希望在更改它们之前对这些变量进行本地化,因为如果不这样做,更改可能会影响依赖于已更改的特殊变量的默认值的其他模块.这是一次读取整个文件的正确方法之一:

  1. 打开我的$ fh,"<","foo"或死!$;
  2. 当地$ /; #enable localized slurp mode
  3. 我的$ content =;
  4. 关闭$ fh;

但是下面的代码非常糟糕:

  1. 打开我的$ fh,"<","foo"或死!$;
  2. undef $ /; #enable slurp mode
  3. 我的$ content =;
  4. 关闭$ fh;

由于某些其他模块,可能想要从默认的"行模式"中读取某些文件中的数据,因此如果我们刚刚提交的代码已经执行,则$ /的全局值现在会针对在其中运行的任何其他代码进行更改Perl翻译.

通常,当变量本地化时,您希望确保此更改影响可能的最短范围.因此,除非你已经进入了一些短的{}块,否则你应该自己创建一个.例如:

  1. 我的$ content ='';
  2. 打开我的$ fh,"<","foo"或死!$;
  3. {
  4. 当地$ /;
  5. $ content =;
  6. }
  7. 关闭$ fh;

以下是您自己的代码如何破坏的示例:

  1. for(1..5){
  2. nasty_break();
  3. 打印"$ _";
  4. }
  5. sub nasty_break {
  6. $ _ = 5;
  7. #用$ _做点什么
  8. }

您可能希望打印此代码:

  1. 1 2 3 4 5

但相反,你得到:

  1. 5 5 5 5 5

为什么?因为nasty_break()会修改$ _而不首先对其进行本地化.修复是添加local():

  1. local $ _ = 5;

  • 我不会说只使用$ _不是最佳做法.对于简短的脚本,它只是有用的.如果你可能不使用它为什么它在那里? (2认同)
  • @Peer - "如果你可能不使用它为什么会在那里?".没有人说你**可能不会**使用它.仅仅是你经常不应该**因为使用它 - 就像一堆其他功能 - 更容易产生错误和/或难以阅读和难以维护的代码. (2认同)