perl基础-2
函数参数
perl 函数参数为$$,$$$,$@
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 /
perl基础-2的更多相关文章
- Perl基础速成
本文是针对没有Perl基础,但想用perl一行式命令取代grep/awk/sed的人,用于速学Perl基础知识. Perl一行式系列文章:Perl一行式程序 perl的-e选项 perl命令的-e选项 ...
- Perl 基础语法
Perl 基础语法 Perl借用了C.sed.awk.shell脚本以及很多其他编程语言的特性,语法与这些语言有些类似,也有自己的特点. Perl 程序有声明与语句组成,程序自上而下执行,包含了循环, ...
- 2.Perl基础系列之入门
官网提供的入门链接:http://perldoc.perl.org/perlintro.html 语法概述 Perl的安装步骤省略,直接去官网下载并按照提示安装即可. 如果Perl安装没问题,那么运行 ...
- perl基础-1
基础 向函数中传递两个数组,使用指针 sub getSql{(my a,my b)=@_;my @array=@$a;} my @a;my @b; getSql(\@a,\@b); length($s ...
- perl基础:传递hash类型参数
1 如果是只有一个参数要传,且是hash,最直接想到的办法就是像传其他类型参数一样直接传, 如: subFuntion(%hash1); 2 如果有多于一个参数要传,这里假设只有一个参数的类型是h ...
- perl基础
perl比较好的博客:http://www.cnblogs.com/cosiray/archive/2012/03/18/2404371.html 以分析一个简单的pm文件为例 # # オプションの取 ...
- 1.Perl基础系列之WHAT、WHY、HOW
What? Perl,一种功能丰富的计算机程序语言,运行在超过100种计算机平台上,适用广泛,从大型机到便携设备,从快速原型创建到大规模可扩展开发. Why? Perl追求简洁快速地解决问题,可很方便 ...
- Perl基础(1)chop与chomp的区别
chop是去掉字符串的最后一个字符 chomp是去掉"$/"指定的结尾符号 测试程序一: [perl] #!/bin/perl $tmp = "sincere" ...
- perl基础01
参考:Perl教程 1.Perl简介 Perl是Practical Extraction and Report Language的缩写,它是由Larry Wall设计的. Perl具有高级语言的强大能 ...
- Perl基础语法
一.脚本文件perl 代码可以写在一个文本文件中,以 .pl..PL 作为后缀.文件名可以包含数字,符号和字母,但不能包含空格,可以使用下划线(_)来替代空格.一个简单的Perl 文件名:rurun_ ...
随机推荐
- 字符串转数组(php版)
思路: 1.判断当前传来的值是否为数组 2.若不是现将传来的值转换为字符串类型 3.判断当前值是否为空 4.若不为空,采用正则进行匹配,如下图 preg_match('/^{.*?}$/', $str ...
- JS正则之---HTML版
话不多说 上代码 <html><head> <meta http-equiv="Content-Type" content="text/h ...
- IDEA导入外部code style
至于用何种代码风格, 根据自己团队规范来吧 提供一个Google的IDEA java风格吧 Github地址 原文地址:https://blog.csdn.net/sasuke__/article/d ...
- java程序中访问https时,报 PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
在java中使用https访问数据时报异常: Caused by: sun.security.validator.ValidatorException: PKIX path building fail ...
- FTP服务器上传,下载文件
public class FtpUtil { /** * * @param host FTP服务器地址 * @param port FTP服务器端口 * @param username FTP登录账号 ...
- VS2017 VS2019 无法进入安装界面闪退问题(windows7SP1)
如果离线安装 Visual Studio 2017/2019出现“即将完成…一切即将准备就绪.”的画面后,等几秒安装程序没有任何错误提示就关闭了,无法继续安装. 解决方法: 将vs_enterpris ...
- mysql设置自增id清零 auto_increment
清空表数据之后,如何让自增id清零,即从0开始计数呢 ; 想让id从1开始,就让 AUTO_INCREMENT = 1 就行了.
- MST-prim ElogV
#include<bits/stdc++.h> #define ll long long using namespace std; ; ; struct node { int t;int ...
- java 文件上传与解析(excel,txt)
excel上传与解析 https://blog.csdn.net/zsysu_it/article/details/79074067 txt解析 https://blog.csdn.net/CSDNw ...
- Java文档查看
对于Java学习者来说,阅读Java文档是必不可少的步骤,比如我现在想知道List接口的retianAll()方法,该怎么办呢? 当然是百度了!!! 皮一下,当然是查找Java文档了,以JDK1.7版 ...