gpt4 book ai didi

perl - 可以在 perl 中定义一个变量,其值不能在子例程中更改吗?

转载 作者:行者123 更新时间:2023-12-05 08:49:30 24 4
gpt4 key购买 nike

在下面的脚本中,我在主程序中声明并修改了@basearray。在 dosomething 子例程中,我访问 @basearray,将其分配给脚本的本地数组,然后修改本地副本。因为我一直很小心地只更改子例程内的局部变量的值,所以 @basearray 没有改变。

但是,如果我在子例程内错误地为 @basearray 赋值,那么它会被更改并且该值会在子例程调用后保留。

这在第二个子例程 doagain 中进行了演示。

此外,doagain 接收引用 \@basearray 作为参数,而不是直接访问 @basearray。但是,去那个额外的麻烦并不能提供额外的安全。为什么要这样做?

有没有办法保证我不会无意中更改任何子例程内的@basearray?我可以在我的代码中构建任何类型的硬安全设备,类似于 use strict;,可能是 mylocal 的某种组合?

我是否正确地认为答案是否定的,唯一的解决方案是不要犯粗心的程序员错误?

#!/usr/bin/perl
use strict; use warnings;
my @basearray = qw / amoeba /;
my $count;

{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}

sub dosomething
{
my $sb_name = (caller(0))[3];
print "entered $sb_name\n";
my @sb_array=( @basearray , 'dog' );
{
print "\@sb_array==\n";
$count = 0;
foreach my $el (@sb_array) { $count++; print "$count:\t$el\n" };
}
print "return from $sb_name\n";
}

dosomething();
@basearray = ( @basearray, 'rats' );

{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}


sub doagain
{
my $sb_name = (caller(0))[3];
print "entered $sb_name\n";
my $sf_array=$_[0];
my @sb_array=@$sf_array;
@sb_array=( @sb_array, "piglets ... influenza" );
{
print "\@sb_array==\n";
$count = 0;
foreach my $el (@sb_array) { $count++; print "$count:\t$el\n" };
}
print "now we demonstrate that passing an array as an argument to a subroutine does not protect it from being globally changed by programmer error\n";
@basearray = ( @sb_array );
print "return from $sb_name\n";
}
doagain( \@basearray );

{
print "\@basearray==\n";
$count = 0;
foreach my $el (@basearray) { $count++; print "$count:\t$el\n" };
}

最佳答案

没有 pragma 或关键字等,但有完善的“良好实践”,在这种情况下完全解决了您合理思考的问题。

  1. 第一个子程序 dosomething 犯了使用在其范围内可见但在更高范围内定义的变量的错误。相反,始终将需要的数据传递给子例程(在非常清楚的情况下,异常(exception)情况很少见)。

    直接使用来自“外部”的数据违背了函数作为封装过程的想法,通过定义明确且清晰的界面与其用户交换数据。它纠缠(“耦合”)原则上完全不相关的代码部分。在实践中,它也可能非常危险。

    另外,@basearray 在 sub 中被抢夺的事实最好被认为是一个意外——当那个 sub 被移动到一个模块时会怎样?或者引入另一个sub来合并定义了@basearray的代码?

  2. 第二个子元素 doagain 很好地引用了该数组。然后,为了保护调用者中的数据,可以将调用者的数组复制到子本地的另一个数组

    sub doagain {
    my ($ref_basearray) = @_;
    my @local_ba = @$ref_basearray;
    # work with local_ba and the caller's basearray is safe
    }

    局部词法变量的名称当然是任意的,但它们类似于调用者的数据名称的约定可能会有用。

然后,为了安全起见,您可以采用一般做法,始终将输入变量复制到本地变量。直接使用仅在您想要更改调用者的数据时传入的引用(在 Perl 中相对较少)。如果对大量数据进行了大量操作,或者涉及非常大的数据结构,这可能会降低效率。所以也许然后通过引用更改数据,并格外小心。

关于perl - 可以在 perl 中定义一个变量,其值不能在子例程中更改吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63957733/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com