函数参数

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的更多相关文章

  1. Perl基础速成

    本文是针对没有Perl基础,但想用perl一行式命令取代grep/awk/sed的人,用于速学Perl基础知识. Perl一行式系列文章:Perl一行式程序 perl的-e选项 perl命令的-e选项 ...

  2. Perl 基础语法

    Perl 基础语法 Perl借用了C.sed.awk.shell脚本以及很多其他编程语言的特性,语法与这些语言有些类似,也有自己的特点. Perl 程序有声明与语句组成,程序自上而下执行,包含了循环, ...

  3. 2.Perl基础系列之入门

    官网提供的入门链接:http://perldoc.perl.org/perlintro.html 语法概述 Perl的安装步骤省略,直接去官网下载并按照提示安装即可. 如果Perl安装没问题,那么运行 ...

  4. perl基础-1

    基础 向函数中传递两个数组,使用指针 sub getSql{(my a,my b)=@_;my @array=@$a;} my @a;my @b; getSql(\@a,\@b); length($s ...

  5. perl基础:传递hash类型参数

    1 如果是只有一个参数要传,且是hash,最直接想到的办法就是像传其他类型参数一样直接传, 如:   subFuntion(%hash1); 2 如果有多于一个参数要传,这里假设只有一个参数的类型是h ...

  6. perl基础

    perl比较好的博客:http://www.cnblogs.com/cosiray/archive/2012/03/18/2404371.html 以分析一个简单的pm文件为例 # # オプションの取 ...

  7. 1.Perl基础系列之WHAT、WHY、HOW

    What? Perl,一种功能丰富的计算机程序语言,运行在超过100种计算机平台上,适用广泛,从大型机到便携设备,从快速原型创建到大规模可扩展开发. Why? Perl追求简洁快速地解决问题,可很方便 ...

  8. Perl基础(1)chop与chomp的区别

    chop是去掉字符串的最后一个字符 chomp是去掉"$/"指定的结尾符号 测试程序一: [perl] #!/bin/perl $tmp = "sincere" ...

  9. perl基础01

    参考:Perl教程 1.Perl简介 Perl是Practical Extraction and Report Language的缩写,它是由Larry Wall设计的. Perl具有高级语言的强大能 ...

  10. Perl基础语法

    一.脚本文件perl 代码可以写在一个文本文件中,以 .pl..PL 作为后缀.文件名可以包含数字,符号和字母,但不能包含空格,可以使用下划线(_)来替代空格.一个简单的Perl 文件名:rurun_ ...

随机推荐

  1. vue : 无法加载文件 C:\Users\lihongjie\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 htt ps:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。 所在位置 行:1 字符: 1 + vue init webpack vue_p

    以管理员方式打开powershell 运行命令:set-ExecutionPolicy RemoteSigned 出现: 执行策略更改执行策略可帮助你防止执行不信任的脚本.更改执行策略可能会产生安全风 ...

  2. python进程之间的通信——Queue

    我们知道进程之间的数据是互不影响的,但有时我们需要在进程之间通信,那怎么办呢? 认识Queue 可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息 ...

  3. 如何用纯 CSS 绘制一个世界上不存在的彭罗斯三角形

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/RyvgMZ 可交互视频教 ...

  4. 牛客 545A 小A与最大子段和 & CF 660F Bear and Bowling 4

    大意: 给定序列$a$, 求选择一个子区间$[l,r]$, 使得$\sum\limits_{i=l}^r(i-l+1)a_i$最大. $n\le2e5, |a_i|\le 1e7$. 记$s[i]=\ ...

  5. 使用xpath爬取猫眼电影排行榜

    最近在学习xpath,在网上找资料的时候,发现一个新手经常拿来练手的项目,爬取猫眼电影前一百名排行的信息,很多都是跟崔庆才的很雷同,基本照抄.这里就用xpath自己写了一个程序,同样也是爬取猫眼电影, ...

  6. Flask与微信小程序登录(后端)

    开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步.这篇文章将介绍 python + flask + 微信小程序实现用户快速注册登录方案(本文主要进行后 ...

  7. springboot配置文件之yml的语法学习

    springboot配置文件(.yml/.yaml.properties) YAML(YAML Ain't Markup Language) YAML A Markup Language:是一个标记语 ...

  8. yii的多表查询

    获取用户发布消息的指定消息id的总和点赞数 Yii $productIds = ['2260', '2262', '2263', '2268', '2269']; $plSql = Like::fin ...

  9. Vue的nextTick是什么?

    公司做之前项目的时候,遇到了一些比较困惑的问题,后来研究明白了nextTick的用法. 我们先看两种情况: 第一种: export default { data () { return { msg: ...

  10. js获取7天之前的日期或者7天之后的日期

    js获取7天之前的日期或者7天之后的日期(网上摘取的,记录自己使用) function fun_date(num) { var date1 = new Date(); //今天时间 var time1 ...