-2

我的项目中有这个:

sub get_src_info($) {
        my $package = shift;
        my ($key,$value,$tail) =("","","");
        my (@APT_INFO,$r);

        open APT, "apt-cache showsrc $package|";

        while (<APT>){
                chomp;
                ($key,$value,$tail) = split /:/;
                if (defined ($key) && defined ($value)) {
                        $value =~ s/^\s+|\s+$//;
                        if (defined($tail)) {
                                $value = "$value:$tail";
                        }
                        if ( $key eq "Package" or $key eq "Version" ) {
                                $r->{$key} = $value;
                        }
                }
                if(/^$/) { push @APT_INFO,$r++; }
        }
        close APT;
        return @APT_INFO;
}

我通常use strict用来检查错误。该代码适用于no strict "refs";指令,但没有它就无法运行,产生错误:

Can't use string ("163277181") as a HASH ref while "strict refs" in use at a.pl line 61, <APT> line 45.

第 61 行是: $r->{$key} = $value;

我更喜欢修复我的代码,而不是让它静音,但不知道出了什么问题/如何解决这个问题。

另外,将引用推进以指向下一个对象的正确方法是什么?虽然它有效,但我觉得$r++这里的构造不正确。

提前非常感谢。

4

1 回答 1

2

您将$r变量用作散列引用$r->{$key}和数字$r++。引用 numify 到一个 ID,因此您可以将它们用作数字。但是,您不能将非引用标量用作引用(引用不是指针)。为了明确这一点:

my $reference = { foo => 1 };
my $numified  = 0 + $reference;  # is now 163277181
say $numified->{foo};  # does not work under strict "refs"
# ${"163277181"}{foo} is equivalent: This looks for global variable %163277181

$r您可以通过在新块开始时简单地创建新引用来解决这些问题。您还应该正确地确定其他变量的范围:不要使用全局变量,并在循环APT声明您的$key等变量。

此外,$key永远不能是undefsplit不返回undef值),并且您不应该使用原型。

我想下面的代码会做你想要的:

use autodie; # automatic error handling, e.g. for `open`

sub get_src_info {
  my ($package) = @_;
  my $info = {};
  my @apt_info;

  open my $fh, "-|", "apt", "showsrc", $package; # circumvent the shell for safety
  while (<$fh>) {
    chomp;
    unless (length) {
      push @apt_info, $info;
      $info = {};  # put a new reference into $info
      next;
    }
    my ($key, $value) = split /:/, $_, 2;  # limit number of fragments to 2
    next unless $key eq "Package" or $key eq "Version";
    s/^\s+//, s/\s+$// for $value;  # this trims at *both* ends
    $info->{$key} = $value;
  }

  return @apt_info;
}

有关参考与指针的更多信息:

您不能在内存安全语言中使用指针算术。Perl 就是这样一种内存安全语言。您可以使用的引用类似于 C 中的指针。它们也是类型化的(尽管是动态的),但会自动进行引用计数,因此一旦不需要,就会释放所引用的数据结构。垃圾收集和内存安全的支持者指向更少的错误(例如 double free)和提高生产力,尽管某些算法可能无法优雅地表达。大多数现代语言默认情况下是内存安全的。

即使这是C,并且$r++会指向一个新地址,我也不得不问你:你不应该malloc新内存吗?内存分配在 Perl 中是隐含的。为我们$r = {}提供了一个新的空哈希引用。如果你使用词法变量(with my),释放也会自动发生。

于 2013-08-26T12:47:28.773 回答