尽管经过数小时的修补,perl 数组仍未填充

perl array not populating, despite hours of tinkering

嗯...我有以下代码片段,想知道为什么第二个子例程 search($$) 无法产生结果...而第一个例程 search_item($$$) 执行得非常好(我).

########################
# generate and return a list of users which match only
# one criteria (eg: eyes=2)
#
# $users is a reference to an array of 6-digit hexidecimal user IDs (eg: 000001, 000002, etc)
# $name is the name of the key (or field) to find (eg: 'eyes')
# $value (eg: 2) is compared with the value stored in the key
# if $value matches what's in the $name'd key, then add the uid to a list

sub search_item($$$) {
  my ($users, $name, $value) = @_;
  my @searched;
  foreach my $uid (@$users) {
    my %ustats = user::getUserStats($uid);
    if ($ustats{$name} eq $value) { push @searched, $uid; }
  }

  return @searched;
}

########################
# generate and return a list of users which match
# many criteria (eg: eyes=2, hair=1, etc)
#
# $users is a reference to an array of user IDs (eg: 000001, 000002, etc)
# $terms is a reference to an array of search terms (eg: $terms[0] = "eyes=2";)
sub search($$) {
  my $users = $_[0]; # an array reference
  my $terms = $_[1]; # an array reference
  my @searched;
  my $first = 1;

  foreach my $term (@$terms) {
    # since @$terms is an array of scalars, in the format of 'name=value' pairs
    my $name = $term; $name =~ s/=(.)*//;
    my $value = $term; $value =~ s/$name=//;

    if ($first) {
      # search the given list reference ($users)
      @searched = search_item($users, $name, $value);
      $first = 0; # set to 0 cause now we gotta use @searched
    } else {
      # otherwise use a reference to @searched
      @searched = search_item(\@searched, $name, $value);
    }
  }

  return @searched;
}

我已经设置了数据,所以代码应该 return 1 次命中。数据是正确的,底层功能(例如:getUserStats($))也能完美运行。

用户 000001969696 都有眼睛 =2 所有其他人的眼睛 =1 和 用户 ID 000001 性别=1,所有其他人性别=0

所以...如果我写:

my @users = getUsers();
foreach my $uid (search_item(\@users, 'eyes', 2)) {
  print "$uid<br>\n";
}

我在我的数据库中总共获得了 6 个用户的 2 个匹配(当然,这是正确的结果)。对这些结果感到满意,我 运行 search 例程。

my @terms = ('eyes=2', 'gender=1'); # gender=0 is a boy.  1 is a girl
my @sResults = search(\@users, \@terms);
if (@sResults) {
  foreach my $uid (@sResults) {
    print "$uid<br>\n";
  }
} else {
  print "nothing found!<br>\n";
}

当我祈祷并希望看到“000001”时,我总是看到 "nothing found!"...:(

这似乎是合法的代码……所以……我怎么搞错了伙计们???我没有正确取消引用某些东西吗?还是...取消引用/引用是我困境的根源?我讨厌指针......但是非常有用:p

如果您传递正确的参数,您的代码确实可以正常工作。我最好的猜测是您使用的 eyes=2 之类的字符串包含虚假空格,例如尾随换行符

这是我用来处理你的子程序的测试程序

use strict;
use warnings;
use 5.010;

my %users = (
    '000001' => { eyes => 2, gender => 1 },
    '000002' => { eyes => 1, gender => 0 },
    '000003' => { eyes => 1, gender => 0 },
    '000004' => { eyes => 1, gender => 0 },
    '969696' => { eyes => 2, gender => 0 },
);

sub user::getUserStats {

    my ( $uid ) = @_;

    %{ $users{$uid} };
}

########################
# generate and return a list of users which match only
# one criteria (eg: eyes=2)
#
# $users is a reference to an array of 6-digit hexidecimal user IDs (eg: 000001, 000002, etc)
# $name is the name of the key (or field) to find (eg: 'eyes')
# $value (eg: 2) is compared with the value stored in the key
# if $value matches what's in the $name'd key, then add the uid to a list

sub search_item($$$) {
    my ( $users, $name, $value ) = @_;
    my @searched;
    foreach my $uid ( @$users ) {
        my %ustats = user::getUserStats( $uid );
        if ( $ustats{$name} eq $value ) { push @searched, $uid; }
    }

    return @searched;
}

########################
# generate and return a list of users which match
# many criteria (eg: eyes=2, hair=1, etc)
#
# $users is a reference to an array of user IDs (eg: 000001, 000002, etc)
# $terms is a reference to an array of search terms (eg: $terms[0] = "eyes=2";)
sub search($$) {
    my $users = $_[0];    # an array reference
    my $terms = $_[1];    # an array reference
    my @searched;
    my $first = 1;

    foreach my $term ( @$terms ) {
        # since @$terms is an array of scalars, in the format of 'name=value' pairs
        my $name = $term;
        $name =~ s/=(.)*//;
        my $value = $term;
        $value =~ s/$name=//;

        if ( $first ) {
            # search the given list reference ($users)
            @searched = search_item( $users, $name, $value );
            $first = 0;    # set to 0 cause now we gotta use @searched
        }
        else {
            # otherwise use a reference to @searched
            @searched = search_item( \@searched, $name, $value );
        }
    }

    return @searched;
}

my $users = [ keys %users ];

say for search( $users, [ 'eyes=2', 'gender=1' ] );

输出

000001

下面是我将如何编写行为相同并采用相同参数的类似子例程,但此应用程序的设计中有很多地方不是最佳的

sub search_item {
    my ( $users, $name, $value ) = @_;

    grep {
        my %ustats = user::getUserStats( $_ );
        $ustats{$name} eq $value;
    } @$users;
}

sub search {
    my ($users, $terms) = @_;
    my @searched;

    for my $term ( @$terms ) {
        my ($name, $value) = split /=/, $term;
        @searched = search_item( $users, $name, $value );
        $users = \@searched;
    }

    @searched;
}

但我认为 user::getUserStats 应该被称为 User::get_user_stats(因为 Perl 为全局标识符保留大写字母,例如包名称)并且它应该 return 对散列的引用而不是只是一个列表