【问题标题】:Passing the value of a global variable inside a subroutine在子例程中传递全局变量的值
【发布时间】:2018-07-10 02:34:59
【问题描述】:

下面是我写的sn-p代码,这里的问题是$server变量不能在子程序内部传递。如何在子例程中传递全局变量的值。请帮忙!

    use strict;
    use warnings;

    my (@list,$server);

    @list = qw/server1.net server2.net server3.net/;

    foreach $server(@list) {
    #calling sub-routines
    command1(); 
    command2();
    }

    sub command1 {
    print $server;
    system("command1");
    }

    sub command2 {
    print $server;
    system("command2");
    }

【问题讨论】:

  • 为什么使用全局变量而不是将变量作为参数传递?
  • 显而易见的答案是将$server 变量传递给子例程(command1($server))。但是您说“问题是 $server 变量不能在子例程中传递”。在这里阻止您这样做会很有趣。
  • (1) 变量不能是局部的,不能传给子程序,这是很不合理的。你必须很好地解释为什么会这样(2)鉴于foreach (@servers) { func() };循环中的$_(每次迭代中的另一个服务器)在子func中看到$_,所以子是sub func { $server = $_ ... }。但这太可怕了,我希望你能正常、明确和透明地传递给函数它需要的东西。

标签: perl subroutine


【解决方案1】:

良好编程最重要的规则之一是减少coupling。减少一段代码对其他代码段的依赖可提高可读性、可维护性并减少出错的机会。

您的 subs 不应依赖于声明和可用的全局变量。 subs 应该有一个服务器参数。

出于同样的原因,您还应该将变量的范围限制在需要它们的地方。

use strict;
use warnings;
use feature qw( say );

sub command1 {
   my ($server) = @_;
   say $server;
   system("command1", $server);
}

sub command2 {
   my ($server) = @_;
   say $server;
   system("command2", $server);
}

{
   my @servers = qw( server1.net server2.net server3.net );

   for my $server (@servers) {
      command1($server); 
      command2($server);
   }
}

【讨论】:

    【解决方案2】:

    .. 如果你想使用全局变量:

    our $server;
    my (@list);
    
    ... rest of the code ...
    

    或者当你想保留它的词汇时,另见Perl foreach loop variable scope

    use strict;
    use warnings;
    
    
    my (@list, $server);
    
    @list = qw/server1.net server2.net server3.net/;
    
    foreach (@list) {
      $server = $_;   # <<-- use it this way
      #calling sub-routines
      command1();
      command2();
    }
    
    sub command1 {
      print $server;
      system("command1");
    }
    
    sub command2 {
      print $server;
      system("command2");
    }
    

    首选:作为参数传递:

    use strict;
    use warnings;
    
    my (@list);
    
    @list = qw/server1.net server2.net server3.net/;
    
    foreach my $server(@list) {
      #calling sub-routines
      command1($server);
      command2($server);
    }
    
    sub command1 {
      my ($server) = @_;
      print $server, "\n";
      system("command1");
    }
    
    sub command2 {
      my ($server) = @_;
      print $server, "\n";
      system("command2");
    }
    

    【讨论】:

    • 你为什么坚持使用包变量作为全局变量?词法是非常好的全局变量。
    • 因为@Borodin 的问题而更新。底线是远离使用全局变量。陷阱很容易制造。在 foreach 中使用 $server 作为词汇并不能达到您的预期
    • @ikegami:local ? : 无法本地化词法变量 $server
    • 哦,抱歉,我以为您使用的是our。通过使用my 而不是our+local,您实际上是在增加范围。
    猜你喜欢
    • 2014-05-14
    • 1970-01-01
    • 2015-08-31
    • 2013-07-16
    • 1970-01-01
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多