【问题标题】:Perl Passing arguments to subroutine not workingPerl将参数传递给子程序不起作用
【发布时间】:2015-06-03 22:52:15
【问题描述】:

我正在尝试将参数传递给 perl 子例程,但无论出于何种原因,子例程内部的参数都是空的。

...
...
...
print "Passing arguments $a, $b, $c, $d \n";
beforeEnd($a, %b, $c, $d);

sub beforeEnd() {
    my ($a, %b, $c, $d) = @_;
    print "a is $a, b is $b, c is $c, d is $d \n";
}

打印语句的输出让我知道出了点问题。奇怪的部分?前 2 个参数正确传递。

> Passing arguments 1, (1,2,3), 2, 3
> a is 1, b is (1,2,3), c is , d is

任何帮助将不胜感激。

【问题讨论】:

  • 您正在传递%b,但正在打印$b
  • 赋值中的列表变量将接收函数的所有剩余参数。
  • 如果你想传递一个列表而不把它作为单独的参数展开,你应该使用数组引用。

标签: perl parameters subroutine


【解决方案1】:

当参数被传递给 Perl 子例程时,它们被扁平化为一个由@_ 表示的列表。从概念上讲,这意味着如果您不传递对数组或散列的引用,您将“丢失”一些数据。 “输”并不完全正确,因为所有的数据都还在;它只是不在您期望的变量中。这方面的一个例子可能是:

sub f {
   my (@a, @b) = @_;

   say 'a: ' . join(', ', @a);
   say 'b: ' . join(', ', @b);
}
f( qw(1 2 3), qw(a b c) );

你会得到以下输出:

a: 1, 2, 3, a, b, c
b: 

发生这种情况是因为第一个数组@a 消耗了来自@_ 的所有值,并且没有更多的值可以存储在@b 中。你的 beforeEnd 子例程中的散列也发生了同样的事情。 $c$d 的值存储在 %b 中。作为一个例子,因为我看不到变量值,如果你通过了

beforeEnd(1, ( a => 1, b => 2 ), 'c', 3);

在您的潜艇中,您会得到如下内容:

$a = 1
%b = ( a => 1, b => 2, c => 3 )
$c = undef
$d = undef 

您可以通过传递对哈希 %b 的引用来解决此问题:

beforeEnd($a, \%b, $c, $d);

【讨论】:

    【解决方案2】:

    因为当您将参数传入或传出子例程时,任何散列和数组都会被粉碎。

    您正在分配给%b,这将吞噬所有参数。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use Data::Dumper;
    
    sub test1 {
        my ( $first, @rest, $last ) = @_;
    
        print Dumper \@rest;
    
        print "First = $first, last = $last, rest = @rest\n";
    }
    
    sub test2 { 
       my ( $first, $second ) = @_;
       print "@$first ; @$second"; 
    }
    
    test1 ( 1, 2, 3, 4 ); 
    test2 ( [1,2], [ 3,4] );
    
    my @list1 = ( 1,2,3,4 );
    my @list2 = ( 5,6,7,8 );
    
    test1 ( @list1, @list2 );
    test2 ( \@list1, \@list2 );
    

    如果您想保持数组或哈希值不变,您需要通过引用或作为最后一个参数传递它们。

    如果您在此处打开strictwarnings,您也可能会收到警告——这是强烈推荐的原因之一——因为$b%b 不一样。您还会收到有关奇数分配的警告:

    Odd number of elements in hash assignment at line 5.
    Use of uninitialized value $b in print
    

    【讨论】:

      【解决方案3】:

      子例程接受标量列表作为参数。如果传递数组或散列,则传递数组或散列的内容。这意味着

      f($a, %b, $c, $d)
      

      相同
      f($a, $b_key_1, $b_val_1, $b_key_2, $b_val_2, $b_key_3, $b_val_3, $c, $d);
      

      @_ 中的多少标量应该分配给%b? Perl 保持简单并分配所有剩余的标量,所以

      my ($a, %b, $c, $d) = @_;
      

      其实和

      没什么区别
      my $a = $_[0];        # The first argument
      my %b = @_[1..$#_];   # All but the first argument
      my $c;
      my $d;
      

      最好传递对哈希的引用。这样就避免了这个问题,而且效率更高。

      use Data::Dumper qw( Dumper );
      
      sub beforeEnd {
          my ($a, $b, $c, $d) = @_;
          local $Data::Dumper::Terse = 1;
          print "a is $a, b is ".Dumper($b).", c is $c, d is $d \n";
      }
      
      beforeEnd($a, \%b, $c, $d);
      

      关于你的代码的题外话:

      • 您有一个原型,表明不需要参数(),但您需要四个。摆脱那个原型。

      • 您应该避免使用 $a$b 作为变量,因为它可能与 sort 产生问题。

      【讨论】:

        【解决方案4】:

        参数只能作为标量变量列表在子程序中传递。

        每当将参数传递给子程序时,我们都需要传递哈希(或数组、对象)的引用。 ... ... ... print "传递参数 $a, $b, $c, $d \n"; beforeEnd($a, \%b, $c, $d);

        sub beforeEnd() {
            my ($a, $b, $c, $d) = @_;
            print "a is $a, b is %$b, c is $c, d is $d \n";
        }
        

        【讨论】:

          猜你喜欢
          • 2014-09-12
          • 2021-04-03
          • 1970-01-01
          • 2021-03-09
          • 2023-03-03
          • 2014-12-12
          • 1970-01-01
          • 2019-10-05
          • 1970-01-01
          相关资源
          最近更新 更多