设为首页 收藏本站
查看: 875|回复: 0

[经验分享] perl函数原型

[复制链接]

尚未签到

发表于 2015-12-25 15:32:46 | 显示全部楼层 |阅读模式
  CU上的翻译
  =head1 prototype
Perl 可以通过函数元型在编译期进行有限的参数类型检验。如果你声明
     sub mypush (+@)
那么 mypush() 对参数的处理就同内置的 push() 完全一样了。函数声明必须要在编译
相应函数调用之前告知编译器(编译器在编译函数调用时会对相应函数用 prototype
来查询它的元型来进行参数检验,并决定怎样编译此函数调用)。元型只在不用 & 调用
函数的时候起作用。就是说在语法上如果你想像内置函数一样调用,它就表现的像
内置函数一样。如果想用过时的风格通过 & 调用,那么编译器就无视函数声明。另外
元型在函数引用如 \&foo 和间接调用如 &{$subref} 和 $subref->() 时也不起作用。
方法调用也不受元型影响,因为实际调用的函数无法在编译期决定,它是由继承关系
决定的。
因为这个特性最初的目的是使你可以像内置函数那样调用自己的函数,所以下面就给出
等价于内置函数调用方式的函数元型。
     声明为                  调用方式
     sub mylink ($$)         mylink $old, $new
     sub myvec ($$$)         myvec $var, $offset, 1
     sub myindex ($$;$)      myindex &getstring, "substr"
     sub mysyswrite ($$$;$)  mysyswrite $buf, 0, length($buf) - $off, $off
     sub myreverse (@)       myreverse $a, $b, $c
     sub myjoin ($@)         myjoin ':', $a, $b, $c
     sub mypop (+)           mypop @array
     sub mysplice (+$$@)     mysplice @array, 0, 2, @pushme
     sub mykeys (+)                mykeys %{$hashref}
     sub myopen (*;$)            myopen HANDLE, $name
     sub mypipe (**)                mypipe READHANDLE, WRITEHANDLE
     sub mygrep (&@)                mygrep { /foo/ } $a, $b, $c
     sub myrand (;$)                myrand 42
     sub mytime ()                mytime
任何 \ 跟着的函数元型中的字符代表着实际的参数必须由相应字符开头(参数前可跟
my our local 声明),只有 $ 例外,它可以接收并不以 $ 开头的 hash 和数组的元素,
比如 my_function()->[0]。传给 @_ 的参数将会是相应实际参数的引用,即对它加 \。
你可以用 \[] 来表示多个可用的类型。比如:
     sub myref (\[$@%&*])
上面的函数声明允许像下面这样调用 myref() 这个函数
     myref $var
     myref @array
     myref %hash
     myref &sub
     myref *glob
传入函数 myref 的第一个参数将分别是一个 scalar、数组、hash、函数、glob 的引用。
函数元型中前面不跟 \ 的字符有特殊意义。任何不跟 \ 的 @ % 将代表剩下的所有参数,
并提供 list context。而 $ 将提供 scalar context。 & 表示需要一个匿名函数(即
sub { } 这样的结构,不能是变量),当用作第一个参数时可以省掉 sub 关键字(如果
省掉 sub 则后面跟的逗号也必须要省掉).
* 表明可以接收一个 bareword、常量、scalar 表达式、typeglob或 typeglob 的引用。
传入函数的参数要么是一个简单的 scalar 要么是 typeglob 的引用(后两种情况)。如果
你总是想要一个 typeglob 的引用可以用 Symbol::qualify_to_ref() 将名字转换成相应
的 typeglob 的引用:
     use symbol 'qualify_to_ref';
     sub foo (*) {
         my $fh = qualify_to_ref(shift, caller);
         ...
     }
+ 类似于 $ 但是当遇到数组变量或 hash 变量时表示 \[@%],在其它情况下总是提供
scalar context。它适用于可以接收数组变量或数组引用为参数的函数:
     sub mypush (+@) { # 5.14 中 push 第一个参数可以为数组的引用
         my $aref = shift;
         die "Not an arrayref" unless ref $aref eq 'ARRAY';
         push @$aref, @_;
     }
当用 + 时函数必须要检验实际的参数是否是自己需要的类型,因为它不区分 @ %。
分号 ; 用来分隔必须的参数和可选的参数。它必须在 @ % 之前,因为它们代表剩下的
所有参数。
在元型最后或在 ; 之前可以用 _ 来代替 $:它表示如果没有提供这个参数会传递 $_
作为对应的参数,它可以用来实现默认参数的语法。
注意上面列表最后3个例子,mygrep() 表现的就像列表操作符,myrand() 表现的就像
rand() 一样为一元操作符,mytime() 就像 time() 一样完全不需要参数。如果你这么用:
     mytime + 2;
你将会得到 mytime() + 2,而不是 mytime(2),没有函数元型根本无法实现这样的效果。
有意思的是你可以把 & 用在最开始的位置来创造新语法:
     sub try (&@) {
         my ($try, $catch) = @_;
         eval { &$try };
         if ($@) {
             local $_ = $@;
             &$catch;
         }
     }
     sub catch (&) { $_[0] }
     try {
         die "phooey";
     } catch {
         /phooey/ and print "unphooey\n";
     };
上面的代码会打印 "unphooey",即是 Try::Tiny 的实现方法。(当然用 &$catch 会
将 @_ 暴露给 $catch 但这里并不是我们要考虑的)。
让我们重新实现下 Perl 的 grep 操作符:
     sub mygrep (&@) { # 无法实现 grep EXPR,LIST 这个语法
         my $code = shift;
         my @result;
         foreach $_ (@_) {
             push @result, $_ if &$code;
         }
         @result;
     }
请不在要函数元型中使用字母或数字,它们被保留作它用,或许在将来用于实现完整的
参数列表。不要为老的代码添加上函数元型,因为有时会改变语意出来奇怪的结果。比如:
     sub func ($) {
         my $n = shift;
         print "you ave me $n\n";
     }
某人在代码中这么调用它:
     func(@foo);
     func(split /:/);
只是声明了函数 func 只接收一个 scalar 参数却带来了灾难性的结果,原来参数所处的
list context 被改为 scalar context,传入的参数变成 @foo 的元素个数,和分割的
元素个数。
元型很强大也很危险,请小心慎用。
  
  以两个数组为参数的函数原型



sub test(\@\@) {
my ($ref_array1, $ref_array2) = @_;
print @{$ref_array1}, "\n";
print @{$ref_array2}, "\n";
}
my @array1 = (1, 2, 3);
my @array2 = (4, 5, 6);
test(@array1, @array2)
  注意调用的时候,不要加&,因为&会忽略所有的函数原型检查。
  一般来说,函数原型能实现的功能,用非函数原型都能实现,比如上面的代码用下面的方式也能实现,采用数组的引用。



sub test {
my ($array1, $array2) = @_;
print @{$array1}, "\n";
print @{$array2}, "\n";
}
my $array1 = [1, 2, 3];
my $array2 = [4, 5, 6];
test($array1, $array2);
1;
  ==

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156297-1-1.html 上篇帖子: perl-cgi-form 下篇帖子: Perl篇:递归遍历及拷贝文件共享服务器中目录
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表