Perl的隐藏function?
Perl中真正有用但深奥的语言特性是什么,你实际上可以用来做有用的工作?
指南:
- 尝试限制Perl核心而不是CPAN的答案
- 请举个例子和一个简短的描述
隐藏function也可在其他语言中find隐藏function:
(这些都是来自Corion的答案 )
- C
- 达夫的设备
- 便携性和标准
- C#
- 引号用于空格分隔的列表和string
- 别名的命名空间
- Java的
- 静态初始化器
- JavaScript的
- 职能是一等公民
- 阻止范围和closures
- 通过variables间接调用方法和访问器
- ruby
- 通过代码定义方法
- PHP
- 普及的在线文档
- 魔术方法
- 符号参考
- python
- 一行换行
- 甚至可以用自己的function取代核心function
其他隐藏function:
运营商:
- bool准运算符
- 触发器操作员
- 也用于列表build设
-
++
和一元运算符在string上工作 - 重复运算符
- 飞船运营商
- || 运算符(和//运算符)从一组选项中进行select
- 钻石经营者
-
m//
运算符的特殊情况 - 代字符“操作符”
引用构造:
- qw操作员
- 字母可以用作q {}类似结构中的引号分隔符
- 引用机制
语法和名称:
- 印后可以有一个空格
- 您可以使用符号引用给出subs数字名称
- 法律追踪逗号
- 分组整数文字
- 散列片
- 从数组中填充散列的键
模块,Pragma和命令行选项:
- 严格使用和使用警告
- 污点检查
- 深奥的使用-n和-p
- CPAN
-
overload::constant
- IO :: Handle模块
- 安全隔间
- 属性
variables:
- 自动激活
-
$[
variables - 领带
- dynamic范围
- 用单个语句进行variables交换
循环和stream量控制:
- 魔法转到
-
for
一个单一的variables - 继续条款
- 绝望模式
常用expression:
-
\G
锚 -
(?{})
和'(?? {})`在正则expression式中
其他特性:
- debugging器
- 特殊的代码块,如BEGIN,CHECK和END
-
DATA
块 - 新的块操作
- 源filter
- 信号钩
- 地图 ( 两次 )
- 包装内置function
-
eof
函数 -
dbmopen
函数 - 将警告转化为错误
其他技巧和元答案:
- 猫文件,如果需要解压缩gzip
- Perl技巧
也可以看看:
- C的隐藏function
- C#隐藏的function
- C ++的隐藏function
- Java的隐藏function
- JavaScript的隐藏function
- Ruby的隐藏function
- PHP的隐藏function
- Python的隐藏function
- Clojure隐藏的function
当循环遍历文件句柄返回的logging(通常是行)时,触发器操作符可用于跳过第一次迭代,而不使用标志variables:
while(<$fh>) { next if 1..1; # skip first record ... }
运行perldoc perlop
并search“flip-flop”以获取更多信息和示例。
Perl中有很多非显而易见的特性。
例如,你知道签名后可以有一个空格吗?
$ perl -wle 'my $x = 3; print $ x' 3
或者,如果您使用符号引用,则可以提供subs数字名称?
$ perl -lwe '*4 = sub { print "yes" }; 4->()' yes
还有一个“bool”准运算符,返回1表示真实expression式,空string表示为false:
$ perl -wle 'print !!4' 1 $ perl -wle 'print !!"0 but true"' 1 $ perl -wle 'print !!0' (empty line)
其他有趣的东西: use overload
可以重载string文字和数字(例如使他们BigInts或其他)。
这些东西中的许多实际上都是在某个地方logging下来的,或者从logging的function中逻辑地logging下来,但是有些并不是很知名。
更新 :另一个不错的。 下面提到了q{...}
引用构造,但是您知道可以使用字母作为分隔符吗?
$ perl -Mstrict -wle 'print q bJet another perl hacker.b' Jet another perl hacker.
同样,你可以写正则expression式:
m xabcx # same as m/abc/
通过魔术ARGV添加对压缩文件的支持:
s{ ^ # make sure to get whole filename ( [^'] + # at least one non-quote \. # extension dot (?: # now either suffix gz | Z ) ) \z # through the end }{gzcat '$1' |}xs for @ARGV;
(在$ _中引号需要用shell元字符处理文件名)
现在, <>
function将解压所有以“.gz”或“.Z”结尾的@ARGV
文件:
while (<>) { print; }
在Perl中我最喜欢的function之一是使用布尔||
操作员在一组select之间进行select。
$x = $a || $b; # $x = $a, if $a is true. # $x = $b, otherwise
这意味着可以写:
$x = $a || $b || $c || 0;
从$a
, $b
和$c
获取第一个真实值,否则就是默认值0
。
在Perl 5.10中,还有//
运算符,如果已定义,则返回左侧,否则返回右侧。 以下select$a
, $b
, $c
的第一个定义值,否则为0
:
$ x = $ a // $ b // $ c // 0;
这些也可以用于他们的短格式,这是非常有用的提供默认值:
$ x || = 0; #如果$ x是假的,现在它的值为0。 $ x // = 0; #如果$ x是未定义的,现在它的值为零。
Cheerio,
保罗
操作符++和一元 – 不仅适用于数字,还适用于string。
my $_ = "a" print -$_
打印-a
print ++$_
打印b
$_ = 'z' print ++$_
打印aa
由于Perl几乎包含了其他列表中的所有“深奥”部分,所以我会告诉你Perl不能做的一件事情:
Perl不能做的一件事就是在你的代码中使用任意的URL,因为 //
操作符用于正则expression式。
为了防止Perl对您提供的function不甚了解,您可以select一些可能不是很明显的条目:
达夫的设备 – 在Perl中
可移植性和标准性 – 与C编译器相比,使用Perl的计算机可能更多
文件/path操作类 –File :: Find可以在比.Net更多的操作系统上运行
引用空格分隔的列表 和string – Perl允许您为列表和string分隔符select几乎任意的引号
别名命名空间 – Perl通过全局分配来实现这些命名空间 :
*My::Namespace:: = \%Your::Namespace
静态初始化器 – Perl可以在编译和对象实例化的几乎每一个阶段运行代码,从BEGIN
(代码parsing)到CHECK
(解码后) import
(在模块导入) new
(对象实例化)到DESTROY
END
(程序退出)
函数是头等公民 – 就像在Perl中一样
块范围和封闭 – Perl有两个
通过一个variables间接调用方法和访问器 – Perl也是这样做的:
my $method = 'foo'; my $obj = My::Class->new(); $obj->$method( 'baz' ); # calls $obj->foo( 'baz' )
通过代码定义方法 – Perl也允许 :
*foo = sub { print "Hello world" };
Pervasive在线文档 – Perl文档在线,可能也在您的系统上
每当调用“nonexisting”函数时都会调用这些魔术方法 –Perl在AUTOLOAD函数中实现它
符号参考 – 你最好build议远离这些。 他们会吃你的孩子。 但是,Perl当然可以让你的孩子献上嗜血的恶魔。
一行换行 – Perl允许列表分配
甚至可以用自己的function取代核心function
use subs 'unlink'; sub unlink { print 'No.' }
要么
BEGIN{ *CORE::GLOBAL::unlink = sub {print 'no'} }; unlink($_) for @ARGV
Autovivification 。 AFAIK 没有其他语言 。
在Perl中引用几乎任何一种奇怪的string都很简单。
my $url = q{http://my.url.com/any/arbitrary/path/in/the/url.html};
事实上,Perl中的各种引用机制是相当有趣的。 Perl正则expression式引用机制允许您引用任何内容,指定分隔符。 您可以使用几乎任何特殊字符(如#,/,或打开/closures字符,如(),[]或{}。 例子:
my $var = q#some string where the pound is the final escape.#; my $var2 = q{A more pleasant way of escaping.}; my $var3 = q(Others prefer parens as the quote mechanism.);
引用机制:
q:直接引用; 只有需要转义的字符才是结束字符。 QQ:一个解释性的报价; 处理variables和转义字符。 非常适合需要引用的string:
my $var4 = qq{This "$mechanism" is broken. Please inform "$user" at "$email" about it.};
qx:像qq一样工作,但是以非系统的方式作为系统命令执行。 返回从标准生成的所有文本。 (redirect,如果在操作系统中支持,也出来)也用回引号(`字符)。
my $output = qx{type "$path"}; # get just the output my $moreout = qx{type "$path" 2>&1}; # get stuff on stderr too
qr:解释类似于qq,但随后将其编译为正则expression式。 与正则expression式上的各种选项一起工作。 你现在可以传递正则expression式作为variables:
sub MyRegexCheck { my ($string, $regex) = @_; if ($string) { return ($string =~ $regex); } return; # returns 'null' or 'empty' in every context } my $regex = qr{http://[\w]\.com/([\w]+/)+}; @results = MyRegexCheck(q{http://myurl.com/subpath1/subpath2/}, $regex);
QW:非常非常有用的引用操作符。 将引用的一组空白分隔的单词转换为列表。 非常适合在unit testing中填写数据。
my @allowed = qw(ABCDEFGHIJKLMNOPQRSTU VWXYZ { }); my @badwords = qw(WORD1 word2 word3 word4); my @numbers = qw(one two three four 5 six seven); # works with numbers too my @list = ('string with space', qw(eight nine), "a $var"); # works in other lists my $arrayref = [ qw(and it works in arrays too) ];
只要事情变得更加清晰,他们就可以使用它们。 对于qx,qq和q,我很可能使用{}运算符。 使用qw的人最常见的习惯通常是()运算符,但有时候你也会看到qw //。
没有真正隐藏起来,但是很多Perl程序员每天都不了解CPAN 。 这特别适用于那些不是全职程序员的人,也不能全职编程。
“for”语句可以用与Pascal中使用的“with”相同的方式:
for ($item) { s/ / /g; s/<.*?>/ /g; $_ = join(" ", split(" ", $_)); }
您可以将一系列s ///操作等应用于同一个variables,而无需重复variables名称。
注意:上面的(&nbsp;)上的非分隔符空间中隐藏了Unicode,以规避Markdown。 不要复制粘贴:)
引号操作符是我最喜欢的东西之一。 比较:
my @list = ('abc', 'def', 'ghi', 'jkl');
和
my @list = qw(abc def ghi jkl);
更less的噪音,更容易在眼睛。 关于Perl的另一个非常好的事情,那就是在编写SQL时真的会错过,后面的逗号是合法的:
print 1, 2, 3, ;
这看起来很奇怪,但如果你以另一种方式缩进代码,
print results_of_foo(), results_of_xyzzy(), results_of_quux(), ;
给函数调用添加一个额外的参数不需要用前面或后面的行上的逗号来摆弄。 单线改变对其周围线路没有影响。
这使得使用可变参数函数非常令人愉快。 这也许是Perl中最被低估的function之一。
parsing直接粘贴到数据块中的数据的能力。 没有必要保存到程序中打开的testing文件或类似的。 例如:
my @lines = <DATA>; for (@lines) { print if /bad/; } __DATA__ some good data some bad data more good data more good data
新的块操作
我会说扩大语言的能力,创造伪块操作是一个。
-
你声明了一个子类的原型,指出它首先需要一个代码引用:
sub do_stuff_with_a_hash (&\%) { my ( $block_of_code, $hash_ref ) = @_; while ( my ( $k, $v ) = each %$hash_ref ) { $block_of_code->( $k, $v ); } }
-
然后你可以像这样在身体中调用它
use Data::Dumper; do_stuff_with_a_hash { local $Data::Dumper::Terse = 1; my ( $k, $v ) = @_; say qq(Hey, the key is "$k"!); say sprintf qq(Hey, the value is "%v"!), Dumper( $v ); } %stuff_for ;
( Data::Dumper::Dumper
是另外一个半隐藏的gem。)注意你不需要块前的sub
关键字,或者hash之前的逗号。 它最终看起来很像: map { } @list
源filter
此外,还有源filter。 Perl将传递给你的代码,以便你可以操纵它。 这和这个块的操作,几乎都不用试试这种在家的types的东西。
我已经用源代码filter做了一些精巧的事情,例如创build一个非常简单的语言来检查时间,允许短的Perl单行程序做出一些决策:
perl -MLib::DB -MLib::TL -e 'run_expensive_database_delete() if $hour_of_day < AM_7';
Lib::TL
只是扫描“variables”和常量,创build它们并根据需要replace它们。
同样,源filter可能是混乱的,但function强大。 但是他们可能会把debugging器搞乱,甚至可能会用错误的行号打印警告。 我停止使用Damian的开关,因为debugging器将失去所有的能力,告诉我我到底在哪里。 但是我发现你可以通过修改小部分代码来将它们保持在同一行,从而将损害降到最低。
信号钩
通常已经足够了,但并不是那么明显。 这是一个模具处理程序,背驮在旧的。
my $old_die_handler = $SIG{__DIE__}; $SIG{__DIE__} = sub { say q(Hey! I'm DYIN' over here!); goto &$old_die_handler; } ;
这意味着代码中的其他模块想要死的时候,他们都会来找你(除非别人在$SIG{__DIE__}
上进行破坏性覆盖)。 而且你可能会被通知某人的东西是错误的。
当然,对于足够的东西,你可以使用END { }
块,如果你想要做的只是清理。
overload::constant
您可以检查包含您的模块的包中的某种types的文字。 例如,如果你在你的import
sub中使用这个:
overload::constant integer => sub { my $lit = shift; return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit };
这将意味着调用包中每个大于20亿的整数将被更改为Math::BigInt
对象。 (请参阅overload :: constant )。
分组整数文字
当我们在这里。 Perl允许你将大数分成三位数组,并且仍然得到一个可分析的整数。 注2_000_000_000
以上为20亿。
二进制“x”是重复操作符 :
print '-' x 80; # print row of dashes
它也适用于列表:
print for (1, 4, 9) x 3; # print 149149149
污点检查。 启用污点检查后,如果试图将受污染的数据(粗略来说,程序外部的数据)传递给不安全的函数(打开文件,运行外部命令等),perl将会死亡(或警告,使用-t
) 。 编写setuid脚本或CGI或任何其他脚本比提供数据的人员拥有更高特权时,这是非常有用的。
魔法转到 goto &sub
做了一个优化的尾部呼叫。
debugging器。
use strict
use warnings
和use warnings
。 这些可以帮你避免一连串的拼写错误。
基于在Perl 5中实现"-n"
和"-p"
开关的方式,你可以编写一个看起来不正确的程序,包括}{
:
ls |perl -lne 'print $_; }{ print "$. Files"'
它在内部被转换成这个代码:
LINE: while (defined($_ = <ARGV>)) { print $_; }{ print "$. Files"; }
让我们从Spaceship Operator开始吧。
$a = 5 <=> 7; # $a is set to -1 $a = 7 <=> 5; # $a is set to 1 $a = 6 <=> 6; # $a is set to 0
这是一个元回答,但Perl Tips文档包含了Perl可以完成的各种有趣的技巧。 以前的提示存档在线浏览,可以通过邮件列表或primefaces提供订阅。
我最喜欢的一些技巧包括使用PAR构build可执行文件 , 使用autodie自动引发exception ,以及在Perl 5.10中使用switch和smart-match结构。
披露:我是Perl提示的作者和维护者之一,所以我显然认为他们非常重视。 ;)
地图 – 不仅因为它使得代码更具performance力,而且因为它给了我一个更多关于这个“函数式编程”的阅读的冲动。
循环中的continue子句。 它会在每个循环的底部执行,即使是下一个循环。
while( <> ){ print "top of loop\n"; chomp; next if /next/i; last if /last/i; print "bottom of loop\n"; }continue{ print "continue\n"; }
我的投票将用于Perl正则expression式中的(?{})和(?? {})组。 第一个执行Perl代码,忽略返回值,第二个执行代码,使用返回值作为正则expression式。
while(/\G(\b\w*\b)/g) { print "$1\n"; }
\ G锚。 很热 。
m//
运算符有一些不明确的特殊情况:
- 如果你使用
?
作为分隔符,它只能匹配一次,除非你调用reset
。 - 如果您使用
'
作为分隔符模式不插入。 - 如果模式为空,则使用上次成功匹配的模式。
The null filehandle diamond operator <>
has its place in building command line tools. It acts like <FH>
to read from a handle, except that it magically selects whichever is found first: command line filenames or STDIN. Taken from perlop:
while (<>) { ... # code for each line }
Special code blocks such as BEGIN
, CHECK
and END
. They come from Awk, but work differently in Perl, because it is not record-based.
The BEGIN
block can be used to specify some code for the parsing phase; it is also executed when you do the syntax-and-variable-check perl -c
. For example, to load in configuration variables:
BEGIN { eval { require 'config.local.pl'; }; if ($@) { require 'config.default.pl'; } }
rename("$_.part", $_) for "data.txt";
renames data.txt.part to data.txt without having to repeat myself.
A bit obscure is the tilde-tilde "operator" which forces scalar context.
print ~~ localtime;
是相同的
print scalar localtime;
and different from
print localtime;
tie, the variable tying interface.
The "desperation mode" of Perl's loop control constructs which causes them to look up the stack to find a matching label allows some curious behaviors which Test::More takes advantage of, for better or worse.
SKIP: { skip() if $something; print "Never printed"; } sub skip { no warnings "exiting"; last SKIP; }
There's the little known .pmc file. "use Foo" will look for Foo.pmc in @INC before Foo.pm. This was intended to allow compiled bytecode to be loaded first, but Module::Compile takes advantage of this to cache source filtered modules for faster load times and easier debugging.
The ability to turn warnings into errors.
local $SIG{__WARN__} = sub { die @_ }; $num = "two"; $sum = 1 + $num; print "Never reached";
That's what I can think of off the top of my head that hasn't been mentioned.
The goatse operator *
:
$_ = "foo bar"; my $count =()= /[aeiou]/g; #3
要么
sub foo { return @_; } $count =()= foo(qw/abcd/); #4
It works because list assignment in scalar context yields the number of elements in the list being assigned.
*
Note, not really an operator