【问题标题】:Perl - Why does shift lose its value after being used?Perl - 为什么移位在使用后会失去价值?
【发布时间】:2009-11-19 18:00:08
【问题描述】:

此代码有效 - 它采用一组完整的 txt 文件路径并将它们剥离,以便在调用 $exam_nums[$x] 时返回文件名

for (0..$#exam_nums)
{
 $exam_nums[$_] =~ s/\.txt$//; #remove extension
 $exam_nums[$_] =~ s/$dir//g; #remove path
}

当我尝试对单个变量执行此操作时,它不起作用。我正在调用一个子程序并向它发送一个礼物,但变量最后是空的。 (它正在进入 if 语句块,因为那里的其他行运行良好。)这是代码:

呼叫下属:

notify($_);

$_ 来自一个有效的 foreach(@files) 循环

子:

sub notify
{
 if(shift)
 { 
  $ex_num = shift;
  $ex_num =~ s/\.txt$//; #remove extension
  $ex_num =~ s/$dir//g; #remove path
        print $ex_num;
        print "\nanything";
 }
}

我尝试在正则表达式的“删除扩展名”部分删除$,但这没有帮助。

【问题讨论】:

  • 当您遇到这些问题时,请在使用之前打印变量的值,以验证它是否具有您认为的值。
  • @brian - 我喜欢生活在边缘......但说真的......真正的问题是我不知道询问是否存在转变会破坏它......在通过它之前到函数,它会打印。在函数之后,它不会
  • 如果您不知道 Perl 内置函数会做什么,请阅读它的文档。不过,打印前后的值会对您有所帮助。您可以做很多事情来帮助自己,在提问之前您应该尝试这样做。
  • 我明白......有时我什至不知道从哪里开始,因此问题的措辞......我认为这个问题出在正则表达式中,而不是使用 shift(s )

标签: regex perl variables shift


【解决方案1】:

您要换班两次。 if 语句中的第一个移位删除了值,第二个移位什么也没有。 shift 具有实际修改 @_ 的副作用。除了返回第一个元素之外,它还会从@_ 中永久删除第一个元素。

编辑:来自man perlfunc

移位数组 shift 将数组的第一个值移出并返回, 将数组缩短 1 并将所有内容向下移动。如果有 数组中没有元素,返回未定义的值。如果 省略 ARRAY,在词法范围内移动 @_ 数组 子程序和格式,...

【讨论】:

  • 所以当我测试班次时,我实际上是在破坏那个指针?
  • 您正在为数组删除一个项目,测试它是否为真,然后将其丢弃。该项目不再存在,下一个班次获得下一个项目,如果有的话。
  • 我最初认为事情发生的方式是:我向函数发送一个变量 [从@files 数组转移],然后该函数测试它是否完全传递了一个变量 [if(shift)] ,如果是的话,处理它....我不完全理解 shift 和/或 $_ 我想。
  • 我在 perlfunc 联机帮助页中添加了一段引述,它解释得很清楚。 shift 本身作用于@_
  • ....看看当你在没有完全学习基础知识的情况下尝试自学时会发生什么样的事情?
【解决方案2】:

您试图从@_(参数列表)中提取ex_num 参数两次:shift(更改@_)与$_[0] 不同(仅查看第一个元素@_,但不改变它)。见perldoc -f shift

此外,您的函数即将结束 $dir,这可能是您的意图,也可能不是。 (有关闭包的更多信息,请参阅perldoc perlfaq7。)我已将其取出并将其添加为附加函数参数:

sub notify
{
    my ($ex_num, $dir) = @_;
    return unless $ex_num;

    $ex_num =~ s/\.txt$//; # remove extension
    $ex_num =~ s/$dir//g;  # remove path
    print $ex_num . "\n";
}

【讨论】:

  • 子例程可以在有或没有参数的情况下调用,这就是为什么我马上测试它......我知道你要去哪里返回除非,但我实际上需要它挂起即使什么都没有给予它周围
  • 我编写的代码与您的原始代码执行相同(逻辑)的操作:如果没有传递给函数的 ex_num 参数,它什么也不做。如果函数中还有其他事情要做(由于缺乏相关性,您从示例中省略了),您当然不应该短路。 :)
【解决方案3】:

我会使用File::Basename 而不是自己滚动。它允许您将文件路径解析为它们的目录、文件名和后缀。

【讨论】:

    【解决方案4】:

    根据Jim Garrison's 信息,我拉了一个开关来解决问题:

    sub notify
    {
        $ex_num = shift;
        if($ex_num)
        {   
            $ex_num =~ s/\.txt$//; #remove extension
            $ex_num =~ s/$dir//g; #remove path
        }
    }
    

    【讨论】:

      【解决方案5】:

      使用核心模块、局部变量和 Perl 5.10。

      use 5.010;
      use File::Basename;
      
      sub notify {
          my $ex_num = shift;
          my $name = basename($ex_num, '.txt');
          say $name;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-18
        • 2013-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-17
        • 1970-01-01
        相关资源
        最近更新 更多