【问题标题】:How do I pass a Perl array as a scalar into a subroutine?如何将 Perl 数组作为标量传递给子例程?
【发布时间】:2012-05-18 04:45:11
【问题描述】:

这里是一位新生的 Perl 开发人员。我一直在绞尽脑汁,在网上到处搜索,试图弄清楚这一点……很生气,我来找你寻求澄清。

我有以下代码(只剩下相关部分),其余部分正常工作):

my @arrMissingTids;
@arrMissingTids = %hshTids;

my $missingtid;
foreach $missingtid (@arrMissingTids) {
    print "$missingtid\n";
}

这很好,返回我想要在数组中的值:

500000246,500000235,500000185,500000237,500000227,500000252

但是,当我将它传递给子例程并将其包含在变量名中时,它不会提供上面写的列表,而只是提供数字 1。其代码如下:

myqry(@arrMissingTids);

sub myqry($) {

    my $missingtids = @_;

    $sql = "select 
        i.tid i_tid, i.name i_name
        from 
        instrument i
        where i.tid in ($missingtids)";

    print "$sql/n";
}

打印 $sql 返回以下内容:

Select i.tid i_tid, i.name i_name from instrument i where i.tid in (1)

当我希望它返回以下内容时:

Select i.tid i_tid, i.name i_name from instrument i where i.tid in (500000246,500000235,500000185,500000237,500000227,500000252)

提前感谢您提供正确方向的任何指示!

【问题讨论】:

标签: arrays perl scalar


【解决方案1】:

感谢所有帮助。毕竟,我最终摆脱了原型并使用了这段代码,它完美地工作并且是从上面的所有帮助中拼凑而成的:

myqry(@arrTids);

sub myqry {
   $missingtids = join(",",@_);

   .rest of code...
}

【讨论】:

    【解决方案2】:

    这里有三个问题。第一种是使用函数原型,不用了,见Why are Perl 5's function prototypes bad?

    第二个是函数调用和函数本身接收方的类型不匹配。要么两次都使用数组,要么两次都使用数组引用。

    第三个是将数据视为 SQL 查询的一部分,可能会打开SQL injection attack 的大门。这可以通过将查询字符串与占位符组合起来与DBI 一起使用来安全地缓解。

    myqry(@arrMissingTids);
    sub myqry {
        my @missingtids = @_;
        $sql = "select
            i.tid i_tid, i.name i_name
            from
            instrument i
            where i.tid in (" . join(',', ('?') x @missingtids) . ")";
        print "$sql\n";
        # $dbh->selectall_arrayref($sql, {}, @missingtids)
    }
    

    myqry(\@arrMissingTids);
    sub myqry {
        my @missingtids = @{ shift() };
        $sql = "select
            i.tid i_tid, i.name i_name
            from
            instrument i
            where i.tid in (" . join(',', ('?') x @missingtids) . ")";
        print "$sql\n";
        # $dbh->selectall_arrayref($sql, {}, @missingtids)
    }
    

    【讨论】:

    • 更改了处理数据库占位符的代码。好提醒,Joel
    • 感谢 Daxim。我很欣赏这个关于传递 SQL 的小角落。在陡峭的学习曲线上,感谢所有帮助。
    【解决方案3】:

    如果有人还没有提到,这里的原型是个问题:

    sub myqry($) {
    

    考虑一下:

    sub test1($) {
        print "$_\n" foreach @_;
    }
    
    sub test2 {
        print "$_\n" foreach @_;
    }
    
    my @args = ('a', 'b', 'c');
    
    test1(@args);
    test2(@args);      
    

    和输出:

    3
    a
    b
    c
    

    现在您已经意识到标量上下文中的数组只是元素的数量,例如:

    my $n = @args;
    

    $n 是 3。通过将数组传递到子例程中,将其简化为标量,最终得到一个 arg,即数组中元素的数量。然后你这样做:

    my $missingtids = @_;
    

    由于子定义中的($),它总是只有一个(数组已经减少到一个元素)。因此,您得到 1

    0.02 美元:perl 中的 IMO 原型是个坏主意 ;)

    【讨论】:

    • 也许提到了(\@) 原型?
    • 我自己不使用这些,但这看起来比 ($) 更好。
    【解决方案4】:

    问题就在这里:

    my $missingtids = @_;
    

    您在标量上下文中调用数组@_。这意味着您将@_ 中的元素数分配给$missingtids。解决此问题的一种方法是传递数组引用:

    sub myqry {
    
        my $missingtids_ref = shift;
        my @missingtids=@$missingtids_ref;
    
        $sql = "select 
            i.tid i_tid, i.name i_name
            from 
            instrument i
            where i.tid in (" . join(",",@missingtids) . ")";
    
        print "$sql/n";
    }
    

    如需了解更多信息,请查看perldoc perlrefperldoc perldata

    【讨论】:

    • 接受这个作为第一个答案并解决了问题......虽然很好,但帮助很大。我非常感谢所有的反馈!
    【解决方案5】:

    所以你想创建字符串

    ... in (1,2,3,4)
    

    使用join

    myqry(join(',', @arrMissingTids))
    

    但那是由内而外的。这样会更好:

    sub myqry {
        my $missingtids = join(',', @_);
    
        return "select 
            i.tid i_tid, i.name i_name
            from 
            instrument i
            where i.tid in ($missingtids)
        ";
    }
    
    myqry(@arrMissingTids);
    

    【讨论】:

      【解决方案6】:

      未经测试,但可能正确:

      myqry(\@arrMissingTids);
      
      sub myqry($) {
      
          my $missingtids = shift; # or $_[0]
      
          $sql = "select 
              i.tid i_tid, i.name i_name
              from 
              instrument i
              where i.tid in (" . join(',', @{$missingtids}) . ")";
      
          print "$sql/n";
      }
      

      当然,您可以传递数组本身而不是引用,但是您需要更改原型并重写数组引用。但是上面的东西应该能让你继续前进。

      【讨论】:

      • 函数上最好不要使用原型。在几乎所有情况下,破坏的东西远远多于它解决的问题。避开他们。
      • 或至少使用原型(\@) 将数组强制为arrayrefs,而不是强制标量上下文,这几乎肯定不是这里想要的。
      • @goldilocks,我不关注,你的意思是如果myqry($) 的原型,myqry(\@array) 就不能工作?它应该。
      • 哎呀!我的错。我没有注意到引用或随后的@{$dereference}。对不起。
      猜你喜欢
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 2013-08-12
      • 1970-01-01
      • 2021-03-09
      • 1970-01-01
      • 2013-12-24
      • 1970-01-01
      相关资源
      最近更新 更多