perl - 可以在 perl 中定义其值不能在子例程中更改的变量吗?
问题描述
在下面的脚本中,我@basearray
在主程序中声明和修改。在dosomething
子例程中,我访问@basearray
,将其分配给脚本本地的数组,并修改本地副本。因为我一直小心只在子程序里面改变局部变量的值, @basearray
是没有改变的。
但是,如果我在子例程内部分配了一个值的错误@basearray
,它就会被更改,并且在调用子例程之后该值将保持不变。
这在第二个子程序中得到了证明,doagain
.
此外,doagain
将引用\@basearray
作为参数接收,而不是@basearray
直接访问。但是去那个额外的麻烦并不能提供额外的安全性。为什么要这样做呢?
有没有办法保证我不会无意中更改 @basearray
任何子程序?我可以在我的代码中构建的任何类型的硬安全设备,类似于use strict;
,也许是my
和的某种组合local
?
我是否正确地认为答案是否定的,唯一的解决方案是不要犯粗心的程序员错误?
#!/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" };
}
解决方案
没有编译指示或关键字等,但有完善的“良好实践”,在这种情况下完全解决了您合理思考的问题。
第一个 sub
dosomething
犯了使用在其范围内可见但在更高范围内定义的变量的罪过。相反,始终将所需的数据传递给子程序(例外情况很少见,在非常清楚的情况下)。直接使用来自“外部”的数据违背了将函数作为封装过程的想法,通过定义明确且清晰的接口与其用户交换数据。它纠缠(“耦合”)原则上完全不相关的代码部分。在实践中,它也可能是完全危险的。
此外,
@basearray
在 sub 中可以抢夺的事实最好被认为是一个意外——当那个 sub 被移动到一个模块时会发生什么?还是引入另一个子来整合@basearray
定义在哪里的代码?第二个 sub
doagain
很好地引用了该数组。然后,为了保护调用者中的数据,可以将调用者的数组复制到 sub 本地的另一个数组sub doagain { my ($ref_basearray) = @_; my @local_ba = @$ref_basearray; # work with local_ba and the caller's basearray is safe }
局部词法变量的名称当然是任意的,但是它们类似于调用者的数据名称的约定可能是有用的。
然后,为了安全起见,您可以采用一般做法,始终将输入变量复制到本地变量。仅当您想更改调用者的数据时才直接使用传入的引用(在 Perl 中相对较少)。如果处理大量数据或涉及非常大的数据结构,这可能会损害效率。因此,也许然后通过其引用进行异常并更改数据,并且要格外小心。
推荐阅读
- kubernetes - 如何使用 MetalLB 配置 k8s 反向代理服务
- arrays - 通过删除给定的索引从一个信号生成动态数量的数组
- sql - 当我过滤掉 NULL 时,报告中显示类 DBNull{}
- shell - 差异,忽略添加到正确文件的行
- flutter - 无法根据宽度扩展堆栈的子级
- python-textfsm - python textfsm解析接口列表
- python - 模板继承在 Flask 中不起作用
- angular - 为什么我的 Angular 表单不会加载提供的数据?
- azure - 更改日志级别 Azure 自托管网关
- c++ - 从 Qt Creator 运行 valgrind 的各种问题(无限运行,黑屏...)