“Reference found where even-sized list expected” 这是个恼人的 -Perl 编程中的Warnings信息。在实现 -GWA2 的Perl版本时遇到这个问题,而且走了弯路,兹分析及备忘如下。
这个字面意思翻译为在期望为偶数元素列表的地方,发现了引用类型数据。
之所以恼人可能是由于debug时,需要弄清楚函数/方法调用时的pass by value 和pass by reference的异同,而这个细节在越来越“高级”的编程环境中变得不常见,所以真正遇到了,就可能一时糊涂走弯路。
这个 pass by value /call by value 和 pass by reference / call by reference 可以单独开一篇讲,兹简记如下:
“When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller’s variable.
When a parameter is passed by value, the caller and callee have two independent variables with the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.”
-R/j2SL
0. 背景知识,Perl中的Hash及Reference
%hash
Instantiating it: %list = (“steve”=>23, “fred”=>38);
Instantiating a reference to it: $ref = {“steve”=>23, “fred”=>38};
Referencing it: $ref = \%list
Dereferencing it: %{$ref}
Accessing an element: ${$ref}{“steve”} or $ref->{“steve”}
–> -R/n2SI
1. 问题
在 GWA2 的设计中,数据及资源的流转需要经过对象object –> 父类webapp –> filea/ dba –> filedriver/dbdriver –> 实际行为及数据。
这个流转过程中,一个较好地承载数据结构是Hash,Key/Value组对,而在Perl的对象和方法等参数传递过程中,是不支持Hash等,如果将一个Hash作为参数进行传递,则该Hash等key/value会被顺序铺列到一个默认的@_数组中,也即如果期望是这样的:
mysub(my %myhash=(‘k1’=>’v1’, ‘k2’=>’v2’));
而实际运行的结果会等同于这样的:
mysub(my @myarray=(‘k1’, ‘v1’, ‘k2’, ‘v2’));
于是,理想的参数传递就不能使用常规的pass by value, 而要使用pass by reference, 也即,
my %myhash = (‘k1’=>’v1’, ‘k2’=>’v2’);
mysub(\%myhash);
魔鬼般的细节就在这里,产生了类似
Reference found where even-sized list expected
这样的错误,其只是一个warning,但在追求完美的coding style中,warnings是不可接受的。
2. 解决方法
问题的本质是在赋值等号的两边,出现了value和对应的reference时,就会报这样的warning,这是输入方面出现不一致,还是输出方面产生的不一致,排解起来容易走弯路。
warn on ($s,%h) = (1,{}) as on %h = {}
–> -R/v2SJ
问题重现:
my %hash = ();
my $hashref = {};
%hash = $hashref; # Reference found where even-sized list expected
由于Perl遵循 no unnecessary constraints, 所以在对方法和函数的传值时,既可以pass by value 也可以pass by reference, 两者都是允许的,用起来也很随意,因此一不留神可能就会将reference赋值给hash,进而产生警告。在稍微复杂点系统中,debug变得有些恼人。正确的使用方式示例:
sub mysub($){
my %result = ();
….
return \%result;
}
my %hash = (‘k1’=>’v1’, ‘k2’=>’v2’);
my $hashref = {};
$hashref = mysub(\%hash);
%hash = %{$hashref};
3. 扩展
Evaluation Stratragy/求值策略: -R/x12SK
-GWA2 是一套通用网络应用(软件程序)架构系统,基于 -GWA2 可以轻便构建各种网络应用程序, 包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等, 也包括各种企事业单位网上门户,在线交互及服务作业系统等. 还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部。