From f7f696dc49c386b56a30dc7cc26e18275a498cc8 Mon Sep 17 00:00:00 2001 From: swuecho Date: Sun, 31 Mar 2013 11:34:49 -0500 Subject: [PATCH] pod2html --- POD/CN_html/perl.html | 251 ++++++++++++ POD/CN_html/perlbook.html | 17 + POD/CN_html/perlcheat.html | 91 +++++ POD/CN_html/perlcn.html | 65 ++++ POD/CN_html/perlembed.html | 714 +++++++++++++++++++++++++++++++++++ POD/CN_html/perlintro.html | 370 ++++++++++++++++++ POD/CN_html/perllol.html | 188 +++++++++ POD/CN_html/perlobj.html | 261 +++++++++++++ POD/CN_html/perlootut.html | 276 ++++++++++++++ POD/CN_html/perlopentut.html | 424 +++++++++++++++++++++ POD/CN_html/perlreftut.html | 222 +++++++++++ POD/CN_html/perlstyle.html | 128 +++++++ POD/CN_html/perlunitut.html | 88 +++++ POD/CN_html/perlutil.html | 58 +++ POD/CN_html/perlvar.html | 572 ++++++++++++++++++++++++++++ POD/CN_html/perlxstut.html | 624 ++++++++++++++++++++++++++++++ POD/CN_html/pod2html.pl | 41 ++ 17 files changed, 4390 insertions(+) create mode 100644 POD/CN_html/perl.html create mode 100644 POD/CN_html/perlbook.html create mode 100644 POD/CN_html/perlcheat.html create mode 100644 POD/CN_html/perlcn.html create mode 100644 POD/CN_html/perlembed.html create mode 100644 POD/CN_html/perlintro.html create mode 100644 POD/CN_html/perllol.html create mode 100644 POD/CN_html/perlobj.html create mode 100644 POD/CN_html/perlootut.html create mode 100644 POD/CN_html/perlopentut.html create mode 100644 POD/CN_html/perlreftut.html create mode 100644 POD/CN_html/perlstyle.html create mode 100644 POD/CN_html/perlunitut.html create mode 100644 POD/CN_html/perlutil.html create mode 100644 POD/CN_html/perlvar.html create mode 100644 POD/CN_html/perlxstut.html create mode 100644 POD/CN_html/pod2html.pl diff --git a/POD/CN_html/perl.html b/POD/CN_html/perl.html new file mode 100644 index 0000000..410a636 --- /dev/null +++ b/POD/CN_html/perl.html @@ -0,0 +1,251 @@ + + + + perl + + + + +

NAME

+

perl - Practical Extraction and Report Language

+

语法

+

perl [ -sTuU ] [ -hv ] [ -V[:configvar] ] [ -cw ] [ -d[:debugger] ] [ -D[number/list] ] [ -pna ] [ -Fpattern ] [ -l[octal] ] [ -0[octal] ] [ -Idir ] [ -m[-]module ] [ -M[-]'module...' ] [ -P ] [ -S ] [ -x[dir] ] [ -i[extension] ] [ -e 'command' ] [ -- ] [ programfile ] [ argument ]...

+

如果你是一个 Perl çš„åˆå­¦è€…,那么你最好先阅读一下 perlintro, 那是一个为åˆå­¦è€…专门准备的简å•ä»‹ç»ï¼Œä¸ºä½ è®²è§£ä¸€äº› Perl 的基础知识, 并且帮助你é¨æ¸¸äºŽå‰©ä½™çš„å¤§é‡ Perl 文档。

+

为了便于阅读,Perl 手册被分æˆäº†ä¸€ä¸‹å‡ ä¸ªéƒ¨åˆ†ï¼š

+

概è¿°

+
    perl                Perl 概述(本文档)
+    perlintro           为åˆå­¦è€…准备的 Perl 简介
+    perltoc             Perl 文档目录
+
+    activeperl          ActivePerl 概述
+

教程

+
    perlreftut          Perl 引用简介
+    perldsc             Perl æ•°æ®ç»“构介ç»
+    perllol             Perl 高级数æ®ç»“æž„: 数组的数组(二维数组)
+
+    perlrequick         Perl 正则表达å¼å¿«é€Ÿå…¥é—¨
+    perlretut           Perl 正则表达å¼æ•™ç¨‹
+
+    perlboot            Perl OO 入门教程
+    perltoot            Perl OO 教程(一)
+    perltooc            Perl OO 教程(二)
+    perlbot             Perl OO 高级技巧与实例
+
+    perlstyle           Perl 程åºé£Žæ ¼æŒ‡å—
+
+    perlcheat           Perl 夹带
+    perltrap            Perl 陷阱
+    perldebtut          Perl 调试教程
+
+    perlfaq             Perl 常è§é—®é¢˜(FAQ)
+      perlfaq1          普通问题
+      perlfaq2          开始使用和学习 Perl 时碰到的问题
+      perlfaq3          编程工具
+      perlfaq4          æ•°æ®æ“作
+      perlfaq5          文件和格å¼
+      perlfaq6          正则表达å¼
+      perlfaq7          Perl 语言问题
+      perlfaq8          系统交互
+      perlfaq9          网络编程
+

参考手册

+
    perlsyn             Perl 语法
+    perldata            Perl æ•°æ®ç»“æž„
+    perlop              Perl æ“作符和优先级
+    perlsub             Perl å­ç¨‹åº
+    perlfunc            Perl 内建函数
+      perlopentut       Perl open() 教程
+      perlpacktut       Perl pack() 和 unpack() 教程
+    perlpod             Perl POD 文档
+    perlpodspec         Perl POD 文档格å¼è¯´æ˜Ž
+    perlrun             Perl è¿è¡Œå’Œé€‰é¡¹
+    perldiag            Perl 诊断信æ¯
+    perllexwarn         Perl 警告
+    perldebug           Perl 调试
+    perlvar             Perl 预定义å˜é‡
+    perlre              Perl 正则表达å¼é«˜çº§æ•™ç¨‹
+    perlreref           Perl 正则表达å¼å¿«é€Ÿå‚考
+    perlref             Perl 引用高级教程
+    perlform            Perl æ ¼å¼
+    perlobj             Perl 对象
+    perltie             Perl 绑定(将对象éšè—在普通å˜é‡èƒŒåŽ)
+      perldbmfilter     Perl DBM 过滤器
+
+    perlipc             Perl 进程间通信
+    perlfork            Perl fork() 说明
+    perlnumber          Perl 数字符å·
+
+    perlthrtut          Perl 线程教程
+      perlothrtut       以å‰çš„ Perl 线程教程
+
+    perlport            Perl 移æ¤æ‰‹å†Œ
+    perllocale          Perl 区域支æŒ
+    perluniintro        Perl Unicode 介ç»
+    perlunicode         Perl Unicode 支æŒ
+    perlebcdic          考虑将 Perl è¿è¡Œåœ¨ EBCDIC ç¼–ç çš„å¹³å°ä¸Š
+
+    perlsec             Perl 安全
+
+    perlmod             Perl 模å—编程: 入门教程
+    perlmodlib          Perl 模å—编程: 如何书写并使用一个新模å—
+    perlmodstyle        Perl 模å—编程: 编写模å—的规范
+    perlmodinstall      Perl 模å—编程: 如何安装一个 CPAN 上å‘布的模å—
+    perlnewmod          Perl 模å—编程: 准备å‘布自己的模å—
+
+    perlutil            Perl 打包ã€å‘布工具
+
+    perlcompile         Perl 编译器套件介ç»
+
+    perlfilter          Perl source filters
+

Perl 内部实现和 C 语言接å£

+
    perlembed           嵌入 Perl 到你的 C/C++ 程åºä¸­åŽ»
+    perldebguts         Perl debugging guts and tips
+    perlxstut           Perl XS 教程
+    perlxs              Perl XS 编程接å£(API)
+    perlclib            C 标准库的 Perl 替代
+    perlguts            使用 Perl 内部函数扩展 Perl
+    perlcall            从 C 中调用 Perl 时的约定
+
+    perlapi             Perl API 一览
+    perlintern          Perl 内部函数
+    perliol             C API for Perl's implementation of IO in Layers
+    perlapio            Perl 内部 IO 抽象接å£
+
+    perlhack            Perl 黑客指å—
+

杂项

+
    perlbook            Perl 书ç±è®¯æ¯
+    perltodo            Perl 未æ¥å±•æœ›
+
+    perldoc             Look up Perl documentation in Pod format
+
+    perlhist            Perl 修改记录
+    perldelta           相对于å‰ä¸€ä¸ªç‰ˆæœ¬çš„修改
+    perl586delta        5.8.6 版所åšçš„修改
+    perl585delta        5.8.5 版所åšçš„修改
+    perl584delta        5.8.5 版所åšçš„修改
+    perl583delta        5.8.3 版所åšçš„修改
+    perl582delta        5.8.2 版所åšçš„修改
+    perl581delta        5.8.1 版所åšçš„修改
+    perl58delta         5.8.0 版所åšçš„修改
+    perl573delta        5.7.3 版所åšçš„修改
+    perl572delta        5.7.2 版所åšçš„修改
+    perl571delta        5.7.1 版所åšçš„修改
+    perl570delta        5.7.0 版所åšçš„修改
+    perl561delta        5.6.1 版所åšçš„修改
+    perl56delta         5.6 版所åšçš„修改
+    perl5005delta       5.005 版所åšçš„修改
+    perl5004delta       5.004 版所åšçš„修改
+
+    activeperl-release  ActivePerl å‘布日志
+    activeperl-changes  ActivePerl 修订历å²
+
+    perlartistic        Perl Artistic License
+    perlgpl             GNU GPL 许å¯å议内容
+

语言相关

+
    perlcn              Perl 简体中文简介(采用 EUC-CN ç¼–ç )
+    perljp              Perl 日文简介(采用 EUC-JP ç¼–ç )
+    perlko              Perl æœé²œæ–‡ç®€ä»‹(采用 EUC-KR ç¼–ç )
+    perltw              Perl ç¹ä½“中文简介(采用 Big5 ç¼–ç )
+

平å°ç›¸å…³

+
    perlaix             AIX å¹³å°è¯´æ˜Ž
+    perlamiga           AmigaOS å¹³å°è¯´æ˜Ž
+    perlapollo          Apollo DomainOS å¹³å°è¯´æ˜Ž
+    perlbeos            BeOS å¹³å°è¯´æ˜Ž
+    perlbs2000          POSIX-BC BS2000 å¹³å°è¯´æ˜Ž
+    perlce              WinCE å¹³å°è¯´æ˜Ž
+    perlcygwin          Cygwin å¹³å°è¯´æ˜Ž
+    perldgux            DG/UX å¹³å°è¯´æ˜Ž
+    perldos             DOS å¹³å°è¯´æ˜Ž
+    perlepoc            EPOC å¹³å°è¯´æ˜Ž
+    perlfreebsd         FreeBSD å¹³å°è¯´æ˜Ž
+    perlhpux            HP-UX å¹³å°è¯´æ˜Ž
+    perlhurd            Hurd å¹³å°è¯´æ˜Ž
+    perlirix            Irix å¹³å°è¯´æ˜Ž
+    perlmachten         Power MachTen å¹³å°è¯´æ˜Ž
+    perlmacos           Mac OS (Classic) å¹³å°è¯´æ˜Ž
+    perlmacosx          Mac OS X å¹³å°è¯´æ˜Ž
+    perlmint            MiNT å¹³å°è¯´æ˜Ž
+    perlmpeix           MPE/iX å¹³å°è¯´æ˜Ž
+    perlnetware         NetWare å¹³å°è¯´æ˜Ž
+    perlopenbsd         OpenBSD å¹³å°è¯´æ˜Ž
+    perlos2             OS/2 å¹³å°è¯´æ˜Ž
+    perlos390           OS/390 å¹³å°è¯´æ˜Ž
+    perlos400           OS/400 å¹³å°è¯´æ˜Ž
+    perlplan9           Plan 9 å¹³å°è¯´æ˜Ž
+    perlqnx             QNX å¹³å°è¯´æ˜Ž
+    perlsolaris         Solaris å¹³å°è¯´æ˜Ž
+    perltru64           Tru64 å¹³å°è¯´æ˜Ž
+    perluts             UTS å¹³å°è¯´æ˜Ž
+    perlvmesa           VM/ESA å¹³å°è¯´æ˜Ž
+    perlvms             VMS å¹³å°è¯´æ˜Ž
+    perlvos             Stratus VOS å¹³å°è¯´æ˜Ž
+    perlwin32           Windows å¹³å°è¯´æ˜Ž
+

如果你使用的是类 UNIX 系统,那么上述手册页默认情况下安装在 /usr/local/man/ 目录。

+

除此之外,还有大é‡çš„ Perl 模å—的文档。这些附加文档默认被放置在 /usr/local/lib/perl5/man 目录或者是 Perl 库目录下的 man å­ç›®å½• 这里边有一部分附加文档是 Perl 的标准å‘布包中自带的,其余则是自行安装的 第三方模å—的文档。

+

译者注:如果你使用的是 windows å¹³å°ä¸‹çš„ ActiveState Perl,并且安装在了 C:\Perl,那么上述手册页的 html 版本都在 C:\Perl\html 目录,pod 版本则在 C:\Perl\lib\pod 目录。如果你是用 .msi 安装包形å¼å®‰è£…çš„è¯ï¼Œå®‰è£…包就会在 [开始] -> [程åº] -> [ActiveState ActivePerl 5.x] -> [Documentation] è¿™ ä½ç½®ç”Ÿæˆä¸€ä¸ªå¿«æ·æ–¹å¼ï¼Œä½ ç‚¹å‡»å®ƒå°±å¯ä»¥æµè§ˆæ‰€æœ‰çš„ ActivePerl 文档。

+

在ç±» UNIX 环境下,通过正确设置相应的系统文件,或者修改 MANPATH 环境å˜é‡ï¼Œ ä½ å¯ä»¥ä½¿ç”¨ man(1) 程åºæ¥æ‰“开手册页。

+

用以下命令å¯ä»¥çŸ¥é“ä½ çš„ Perl 手册页被安装到了什么地方:

+
    perl -V:man.dir
+

如果返回结果中包å«æœ‰ä¸€ä¸ªå¸¸ç”¨çš„部分,比如是 /usr/local/man/man1 å’Œ /usr/local/man/man3, 那么你åªéœ€è¦æ·»åŠ  (/usr/local/man) 到你的 man(1) çš„é…置文件或者 MANPATH 环境å˜é‡ä¸­ã€‚

+

如果返回结果ä¸åŒ…括这些常用目录,那你åªå¥½å°†æ¯ä¸€è¡Œéƒ½æ·»åŠ åˆ° man(1) çš„é…ç½® 文件或者 MANPATH 环境å˜é‡äº†ã€‚

+

此外,你还å¯ä»¥ç”¨ Perl 自带的 perldoc 脚本æ¥æµè§ˆ Perl æ‰‹å†Œé¡µæˆ–è€…æ¨¡å— æ–‡æ¡£ã€‚(译者注:在 windows å¹³å°ä¸‹ï¼Œå› ä¸ºæ²¡æœ‰ man 命令,所以è¦æƒ³åœ¨å‘½ä»¤è¡Œä¸‹ æµè§ˆ Perl 文档,那么这是唯一的方å¼ã€‚)

+

如果你的程åºä¸èƒ½æ­£ç¡®å·¥ä½œè€Œä½ åˆä¸çŸ¥é“该去看哪个手册页,那么请试一下 -w 命令行选项,它通常会给你一个相对准确的信æ¯ä»¥æŒ‡å‡ºåˆ°åº•æ˜¯å“ªå„¿å‡ºäº†éº»çƒ¦ã€‚

+

说明

+

Perl å¯ä»¥è½»æ˜“的实现扫æä»»æ„文本文件ã€ä»Žä¸­æå–有用的信æ¯ã€ç„¶åŽæŒ‰ç…§è¦æ±‚çš„ æ ¼å¼æ‰“å°å‡ºæŠ¥è¡¨ã€‚Perl 也是一ç§ä¼˜ç§€çš„系统管ç†å·¥å…·ã€‚

+

Perl 语言被设计æˆæ˜¯â€œå®žç”¨çš„â€(易于使用ã€é«˜æ•ˆã€åŠŸèƒ½ä¸°å¯Œ),而ä¸æ˜¯â€œåŽä¸½çš„†(简å•ã€ä¼˜ç¾Žã€ç²¾è‡´)。『译者注:译文无法体现原文的æ„æ€ï¼ŒåŽŸæ–‡ä¸º "The language is intended to be practical (easy to use, efficient, complete) rather than beautiful (tiny, elegant, minimal)."ã€

+

据作者æ¥çœ‹ï¼ŒPerl 结åˆäº† Cã€sedawksh 等一些工具的许多优秀特性。 这样熟悉以上工具的人å¯ä»¥åªèŠ±è´¹è¾ƒå°‘的代价就å¯ä»¥ä½¿ç”¨ Perl。 (语言历å²å­¦å®¶ä»¬ å¯èƒ½è¿˜è®°å¾— csh, Pascal, 甚至还有 BASIC-PLUS.)

+

以下是 Perl 的一些特点: 1, Perl 的表达å¼è¯­æ³•å’Œ C 的表达å¼è¯­æ³•éžå¸¸ç›¸ä¼¼ã€‚ 2, 和大多数 UNIX 工具ä¸åŒï¼ŒPerl 本身ä¸ä¼šé™åˆ¶ä½ çš„æ•°æ®å¤§å°ï¼Œåªè¦ä½ æ‹¥æœ‰è¶³å¤Ÿçš„ 内存。 3, Perl å¯ä»¥ä¸€å£æ°”读å–整个文件的内容并且ä¿å­˜åˆ°ä¸€ä¸ªæ™®é€šçš„字符串å˜é‡ä¸­ã€‚ 4, 递归嵌套层数没有é™åˆ¶ã€‚ 5, 使用“哈希表(hash)â€(有些资料也称作“关è”数组(associative arrays)â€) æ¥ è¡¨ç¤ºè¡¨æ ¼ã€‚åœ¨å¿…è¦çš„时候哈希表会自动增长é¢å¤–的空间以å…妨ç¢åˆ°æ€§èƒ½ã€‚ 6, 使用“模å¼åŒ¹é…â€æ¥å¿«é€Ÿæ‰«æ大é‡æ•°æ®ã€‚ 7, Perl 也å¯ä»¥å’ŒäºŒè¿›åˆ¶æ•°æ®æ‰“交é“,通过æŸäº›æŠ€æœ¯ï¼Œå¯ä»¥ä½¿ä¸€ä¸ª DBM 文件象一个 哈希表一样æ“作。 8, 出于 setuid æ–¹å¼è¿è¡Œçš„ Perl 脚本è¦æ¯”åŒæ ·çš„ C 程åºå®‰å…¨ï¼ŒPerl 拥有一个贯穿 æ•°æ®æµçš„污染检测系统,这å¯ä»¥é˜²æ­¢å¤§å¤šæ•°ä»¤äººç”ŸåŽŒçš„安全æ¼æ´žã€‚

+

如果你碰到了一个任务需è¦ç”¨ sed 〠awk 或者 sh æ¥å®Œæˆï¼Œç»“æžœå´å‘现 无法åšåˆ°æˆ–者是想è¿è¡Œèµ·æ¥æ›´å¿«ä¸€äº›ï¼Œå¹¶ä¸”ä½ åˆä¸æƒ³å†™ C 程åºæ¥å¤„ç†ï¼Œé‚£ä¹ˆ Perl å°± 是你最好的选择。Perl å…许你将现有的 sed 脚本或者 awk 脚本转æ¢ä¸º Perl 脚本。

+

早在 1993 å¹´(å‚è§ perlhist)的时候, Perl 5 几乎被完全é‡å†™äº†ä¸€æ¬¡ï¼Œç»åŽ†äº†è¿™ 次版本更新以åŽï¼ŒPerl 增加了一下几个é‡è¦ç‰¹æ€§ï¼š

+ +

好了,有了以上这些宣传,我想肯定已ç»è¶³å¤Ÿäº†ã€‚

+

可用性

+

在大多数æ“作系统上 Perl 都是å¯ç”¨çš„。实际上所有类 UNIX å¹³å°éƒ½æ˜¯å¯ç”¨çš„。 详情å‚è§ "Supported Platforms" "Supported Platforms" in perlport, 那里有一个清å•ã€‚

+

运行环境

+

参è§ perlrun.

+

作者

+

Larry Wall <larry@wall.org>, 以åŠå…¶ä»–许多普通人

+

如果你认为你的 Perl æˆåŠŸæ¡ˆä¾‹èƒ½å¤Ÿå¸®åŠ©é‚£äº›éœ€è¦åœ¨ä»–们的项目中使用 Perl 的人, 或者你想简å•åœ°è¡¨è¾¾ä¸€ä¸‹ä½ å¯¹äºŽ Larry 以åŠå…¶ä»– Perl å¼€å‘人员的谢æ„,那么请写信 ç»™ perl-thanks@perl.org。

+

文件

+
 "@INC"                 å®šä½ Perl 模å—æœç´¢è·¯å¾„
+

参è§

+
 a2p    awk 脚本到 perl 脚本的翻译器
+ s2p    sed 脚本到 perl 脚本的翻译器
+
+ http://www.perl.org/       Perl 主页
+ http://www.perl.com/       Perl 文章(O'Reilly 维护)
+ http://www.cpan.org/       CPAN: 完整的 Perl 档案网络
+ http://www.pm.org/         Perl Mongers
+

诊æ–­

+

使用 use warnings 语å¥(或者 -w 命令行选项)å¯ä»¥å¾—到很多有用的诊断 ä¿¡æ¯ã€‚

+

查看 perldiag å¯ä»¥å¾—到所有的 Perl 诊断信æ¯çš„解释。使用 use diagnostics 语å¥å¯ä»¥è‡ªåŠ¨åœ°å°†é”™è¯¯ä¿¡æ¯è½¬æ¢æˆæ›´åŠ è¯¦ç»†çš„å½¢å¼ã€‚

+

编译时产生的错误信æ¯å¯ä»¥å‘Šè¯‰ä½ é”™è¯¯å‘生的行å·ï¼Œä»¥åŠå…·ä½“出错的ä½ç½®ã€‚ (译者注:因为 Perl 总是在错误å‘生之åŽæ‰ä¼šå‘现错误,因此实际的错误ä½ç½® 往往è¦æ¯”æ示的é å‰ä¸€äº›)

+

如æžœ Perl 脚本是通过命令行å‚æ•° -e 传递过去的,那么æ¯ä¸€ä¸ª -e å‚æ•° 将被当作一行æ¥è®¡ç®—è¡Œå·ã€‚

+

Setuid 脚本å¯ä»¥æ·»åŠ çº¦æŸï¼Œä»Žè€Œäº§ç”Ÿç±»ä¼¼äºŽâ€œInsecure dependency†(ä¸å®‰å…¨çš„ä¾èµ–) 之类的消æ¯ã€‚å‚è§ perlsec

+

我们是ä¸æ˜¯åº”该æ倡在æ¯ä¸ªç¨‹åºä¸­éƒ½ä½¿ç”¨ -w 开关呢?

+

BUGS

+

-w 命令行选项ä¸æ˜¯å¼ºåˆ¶çš„。

+

Perl 的有些æ“作是和你的机器相关的,比如 type casting(类型转æ¢ï¼‰ã€ atof() æ“作ã€è¿˜æœ‰ä½¿ç”¨ sprintf() 进行浮点数的输出,等等。

+

如果你的标准输入输出库需è¦åœ¨æ¯æ¬¡è¯»æˆ–者写æ“作之åŽç§»åŠ¨æ–‡ä»¶æŒ‡é’ˆï¼Œé‚£ä¹ˆ Perl 中会 åŒæ ·å¦‚此,但是 sysread() å’Œ syswrite() 函数中ä¸ä¼šè¿™æ ·ã€‚

+

尽管没有一ç§å†…建数æ®ç±»åž‹çš„尺寸会å—到除了物ç†å†…存大å°ä¹‹å¤–的其它任何é™åˆ¶ï¼Œä½† 是ä»ç„¶æœ‰ä¸€äº›ä¸œè¥¿åœ¨åˆ¶çº¦ç€ä½ ï¼šå˜é‡å的长度ä¸èƒ½è¶…过 251 个字æ¯ï¼›å¦å¤–,诊断时显示 出æ¥çš„è¡Œå·åœ¨ Perl 内部是使用短整型存储的,因此最大ä¸èƒ½è¶…过 65535(超过这个数 之åŽå°†å‘生环绕)。

+

你å¯ä»¥å°†ä½ å‘现的 bug 汇报到 perlbug@perl.org。ä¸è¿‡æœ€å¥½é™„上一份完整的é…置信 æ¯ï¼Œperl æºä»£ç æ ‘中的 myconfig å¯ä»¥å¸®ä½ åšè¿™ä»¶äº‹ï¼Œæˆ–者用 perl -V 也行。如果 ä½ æˆåŠŸåœ°ç¼–译了 Perl,那么你å¯ä»¥åœ¨ utils/ 目录下找到 perlbug è„šæœ¬ï¼Œå®ƒå¯ ä»¥å¸®åŠ©ä½ é‚®å¯„ä¸€ä»½ bug 报表。

+

Perl 事实上是一个“夭折的垃圾列表器â€ï¼Œä½†æ˜¯åƒä¸‡ä¸è¦å‘Šè¯‰ä»»ä½•äººæˆ‘这么说过。^_^

+

注æ„事项

+

Perl 的格言是“æ¡æ¡å¤§è·¯é€šç½—马â€ï¼ˆThere's more than one way to do it.),具 体有多少作为练习留给读者去猜测好了。

+

程åºå‘˜çš„三ç§ä¸»è¦ç¾Žå¾·æ˜¯ï¼šæ‡’惰ã€æ€¥èºå’Œå‚²æ…¢ã€‚至于为什么这么说请å‚考骆驼书。

+

TRANSLATORS

+

王å…´åŽ "flw" <flw@cpan.org>

+ + diff --git a/POD/CN_html/perlbook.html b/POD/CN_html/perlbook.html new file mode 100644 index 0000000..e9f05ad --- /dev/null +++ b/POD/CN_html/perlbook.html @@ -0,0 +1,17 @@ + + + + perlbook + + + + +

NAME

+

perlbook - Perl 书ç±ä¿¡æ¯

+

DESCRIPTION

+

由 Larry Wall 等人编写的骆驼书 (官方å称为 Perl 语言编程, 第三版) 是一本覆盖 Perl å„个方é¢çš„æƒå¨å‚考著作。 ä½ å¯ä»¥ä»Ž O'Reilly & Associates (è”系电è¯ï¼š1-800-998-9938) 订购该书åŠå…¶ä»– Perl 书ç±ã€‚ 本地/海外è”系电è¯ä¸º +1 707 829 0515。 如果能找到一份 O'Reilly 订货å•ï¼Œä½ ä¹Ÿå¯ä»¥å‘ +1 707 829 0104 å‘é€ä¼ çœŸã€‚ 如果你能上网,å¯ä»¥åˆ° http://www.oreilly.com/ 在线填写订货å•ã€‚

+

其他出自ä¸åŒä½œè€…和出版商的 Perl 书ç±å¯ä»¥åœ¨ perlfaq2 中或 http://books.perl.org/ 的页é¢ä¸Šæ‰¾åˆ°åˆ—表。

+

TRANSLATORS

+

ChaosLawful

+ + diff --git a/POD/CN_html/perlcheat.html b/POD/CN_html/perlcheat.html new file mode 100644 index 0000000..ca3fe15 --- /dev/null +++ b/POD/CN_html/perlcheat.html @@ -0,0 +1,91 @@ + + + + perlcheat + + + + +

NAME

+

perlcheat - Perl 5 速查

+

DESCRIPTION

+

这个“速查â€å®žé™…上是一个真正的“手册â€ï¼ï¼å·´æŽŒå¤§çš„一个å°å†Œå­ï¼Œç”¨æ¥è®°å½• 一些开始学习 Perl 编程时é‡åˆ°çš„知识点。它并ä¸æ˜¯é¢é¢ä¿±åˆ°çš„,但是覆盖了约 194 个 Perl 特性。

+

速查

+

建议你把它打å°å‡ºæ¥ ^_^ 帖在墙上,如果è¦è€ƒè¯•çš„è¯ï¼Œè¿˜å¯ä»¥è—在袖筒里 ^_^

+
  上下文  å˜é‡åå‰ç¼€           数组          哈希表
+  void      $scalar    整个:   @array        %hash
+  scalar    @array     切片:   @array[0, 2]  @hash{'a', 'b'}
+  list      %hash      元素:   $array[0]     $hash{'a'}
+            &sub
+            *glob    æ ‡é‡å€¼ç±»åž‹
+                     数值, 字符串, 引用, glob, undef
+  引用
+  \     引用            $$foo[1]       等效于 $foo->[1]
+  $@%&* 解引用          $$foo{bar}     等效于 $foo->{bar}
+  []    匿å数组        ${$$foo[1]}[2] 等效于 $foo->[1]->[2]
+  {}    匿å哈希表      ${$$foo[1]}[2] 等效于 $foo->[1][2]
+  \()   一列引用
+                          数值 VS 字符串      有用的链接
+  æ“作符优先              =          =        perl.plover.com
+  ->                      +          .        search.cpan.org
+  ++ --                   == !=      eq ne         cpan.org
+  **                      < > <= >=  lt gt le ge   pm.org
+  ! ~ \ u+ u-             <=>        cmp           tpj.com
+  =~ !~                                            perldoc.com
+  * / % x                 语法
+  + - .                   for    (LIST) { }, for (a;b;c) { }
+  << >>                   while  ( ) { }, until ( ) { }
+  命å一元æ“作符          if     ( ) { } elsif ( ) { } else { }
+  < > <= >= lt gt le ge   unless ( ) { } elsif ( ) { } else { }
+  == != <=> eq ne cmp     foreach 任何时候都å¯ä»¥ç¼©å†™ä¸º for
+  &
+  | ^              正则表达å¼å…ƒå­—符           正则表达å¼ä¿®é¥°ç¬¦
+  &&               ^     字符串开始           /i 大å°å†™ä¸æ•æ„Ÿ
+  ||               $     字符串结æŸ(\n之å‰)   /m ^$ 表示行首行末
+  .. ...           +     一个或多个           /s . 包括 \n
+  ?:               *     零个或多个           /x 忽略所有空白
+  = += -= *= 等等  ?     零个或一个           /g 全局(é‡å¤ï¼‰
+  , =>             {3,7} é‡å¤ 3 到 7 次
+  列表æ“作符       ()    æ•èŽ·             正则表达å¼å­—符类
+  not              (?:)  ä¸æ•èŽ·           .  == [^\n]
+  and              []    å­—ç¬¦ç±»æˆ–é›†åˆ     \s == [\x20\f\t\r\n]
+  or xor           |     二选一           \w == [A-Za-z0-9_]
+                   \b    å•è¯è¾¹ç•Œ         \d == [0-9]
+                   \z    字符串结尾       \S, \W and \D negate
+  一定è¦è¿™æ ·åšï¼
+  use strict;        ä¸è¦è¿™æ ·åšï¼     有用的链接
+  use warnings;      "$foo"           perl.com
+  my $var;           $$variable_name  perlmonks.org
+  open() or die $!;  `$userinput`     use.perl.org
+  use Modules;       /$userinput/     perl.apache.org
+                                      parrotcode.org
+  函数返回值
+  stat      localtime    caller         特殊å˜é‡
+   0 dev    0 秒(0-59)   0 åŒ…å         $_    默认å˜é‡
+   1 ino    1 分(0-59)   1 æ–‡ä»¶å       $0    程åºå称
+   2 mode   2 æ—¶(0-23)   2 è¡Œå·         $/    输入分隔符
+   3 nlink  3 æ—¥(1-30)   3 调用å­ç¨‹åº   $\    输出分隔符
+   4 uid    4 月-1(0-11) 4 有没有å‚数? $|    å¥æŸ„ä¸ç¼“冲
+   5 gid    5 å¹´-1900    5 想è¦æ•°ç»„å—? $!    系统错误信æ¯
+   6 rdev   6 星期几     6 eval 文本    $@    eval 错误信æ¯
+   7 size   7 当年第几天 7 is_require   $$    当å‰è¿›ç¨‹å·
+   8 atime  8 是å¦å¤ä»¤æ—¶ 8 hints        $.    当å‰å¥æŸ„当å‰è¡Œå·
+   9 mtime               9 bitmask      @ARGV 命令行å‚æ•°
+  10 ctime  just use                    @INC  模å—æœç´¢è·¯å¾„
+  11 blksz  POSIX::      3..9 åªæœ‰å¸¦å‚  @_    å­ç¨‹åºå‚æ•°
+  12 blcks  strftime!    数调用时有效   %ENV  环境å˜é‡
+

ACKNOWLEDGEMENTS

+

本文的最åˆå‡ºçŽ°åœ¨ Perl Monks 上,åŽæ¥åˆæœ‰ä¸€äº›äººæ出过建议。感谢 Perl Monksï¼

+

特别è¦æ„Ÿè°¢çš„是 Damian Conway,他ä¸ä»…æ了很多é‡è¦çš„修改建议,而且还è€å¿ƒåœ° 数了数一共列出了多少个 Perl 特性,并且还制作了一个 Perl 6 版本。

+

作者

+

本文由 Juerd Waalboer <juerd@cpan.org>, 在很多 Perl Monks 人的帮助下完æˆã€‚

+

参è§

+
 http://perlmonks.org/?node_id=216602      最åˆçš„帖å­
+ http://perlmonks.org/?node_id=238031      Damian Conway 的 Perl6 版本
+ http://juerd.nl/site.plp/perlcheat        Perl 速查主页
+

翻译者åŠç¿»è¯‘声明

+

本文由 flw (flw@cpan.org) 翻译,翻译æˆæžœé¦–次出现在 中国 Perl å会 http://www.perlchina.org) çš„å作开å‘å¹³å°ä¸Šã€‚

+

PerlChina.org 本ç€â€œåœ¨å›½å†…推广 Perlâ€ çš„ç›®çš„ï¼Œç»„ç»‡äººå‘˜ç¿»è¯‘æœ¬æ–‡ã€‚è¯»è€…å¯ ä»¥åœ¨éµå®ˆåŽŸä½œè€…许å¯åè®®ã€å°Šé‡åŽŸä½œè€…åŠè¯‘作者劳动æˆæžœçš„å‰æ下,任æ„å‘布或 修改本文。

+

如果你对本文有任何æ„è§ï¼Œæ¬¢è¿Žæ¥ä¿¡æŒ‡æ•™ã€‚本人éžå¸¸æ¬¢è¿Žä¸Žå„ä½äº¤æµã€‚

+ + diff --git a/POD/CN_html/perlcn.html b/POD/CN_html/perlcn.html new file mode 100644 index 0000000..985af52 --- /dev/null +++ b/POD/CN_html/perlcn.html @@ -0,0 +1,65 @@ + + + + perlcn + + + + +

If you read this file _as_is_, just ignore the funny characters you see. It is written in the POD format (see perlpod manpage) which is specially designed to be readable as is.

+

The following documentation is written in EUC-CN encoding.

+

如果你用一般的文字编辑器阅览这份文件, 请忽略文中奇特的注记字符. 这份文件是以 POD (简明文件格å¼) 写æˆ; è¿™ç§æ ¼å¼æ˜¯ä¸ºäº†èƒ½è®©äººç›´æŽ¥é˜…读, 而特别设计的. 关于此格å¼çš„进一步信æ¯, 请å‚考 perlpod 线上文件.

+

NAME

+

perlcn - 简体中文 Perl 指å—

+

DESCRIPTION

+

欢è¿Žæ¥åˆ° Perl 的天地!

+

从 5.8.0 版开始, Perl 具备了完善的 Unicode (统一ç ) 支æ´, 也连带支æ´äº†è®¸å¤šæ‹‰ä¸è¯­ç³»ä»¥å¤–çš„ç¼–ç æ–¹å¼; CJK (中日韩) 便是其中的一部份. Unicode 是国际性的标准, 试图涵盖世界上所有的字符: 西方世界, 东方世界, 以åŠä¸¤è€…间的一切 (希腊文, å™åˆ©äºšæ–‡, 亚拉伯文, 希伯æ¥æ–‡, å°åº¦æ–‡, å°åœ°å®‰æ–‡, 等等). 它也容纳了多ç§ä½œä¸šç³»ç»Ÿä¸Žå¹³å° (如 PC åŠéº¦é‡‘å¡”).

+

Perl 本身以 Unicode 进行æ“作. 这表示 Perl 内部的字符串数æ®å¯ç”¨ Unicode 表示; Perl 的函å¼ä¸Žç®—符 (例如正规表示å¼æ¯”对) 也能对 Unicode 进行æ“作. 在输入åŠè¾“出时, 为了处ç†ä»¥ Unicode 之å‰çš„ç¼–ç æ–¹å¼å­˜æ”¾çš„æ•°æ®, Perl æ供了 Encode 这个模å—, å¯ä»¥è®©ä½ è½»æ˜“地读å–åŠå†™å…¥æ—§æœ‰çš„ç¼–ç æ•°æ®.

+

Encode 延伸模å—支æ´ä¸‹åˆ—简体中文的编ç æ–¹å¼ ('gb2312' 表示 'euc-cn'):

+
    euc-cn      Unix 延伸字符集, 也就是俗称的国标ç 
+    gb2312-raw  未ç»å¤„ç†çš„ (低比特) GB2312 字符表
+    gb12345     未ç»å¤„ç†çš„中国用ç¹ä½“中文编ç 
+    iso-ir-165  GB2312 + GB6345 + GB8565 + 新增字符
+    cp936       å­—ç é¡µ 936, 也å¯ä»¥ç”¨ 'GBK' (扩充国标ç ) 指明
+    hz          7 æ¯”ç‰¹é€¸å‡ºå¼ GB2312 ç¼–ç 
+

举例æ¥è¯´, å°† EUC-CN ç¼–ç çš„æ¡£æ¡ˆè½¬æˆ Unicode, 祗需键入下列指令:

+
    perl -Mencoding=euc-cn,STDOUT,utf8 -pe1 < file.euc-cn > file.utf8
+

Perl 也内附了 "piconv", 一支完全以 Perl 写æˆçš„字符转æ¢å·¥å…·ç¨‹åº, 用法如下:

+
    piconv -f euc-cn -t utf8 < file.euc-cn > file.utf8
+    piconv -f utf8 -t euc-cn < file.utf8 > file.euc-cn
+

另外, 利用 encoding 模å—, ä½ å¯ä»¥è½»æ˜“写出以字符为å•ä½çš„程åºç , 如下所示:

+
    #!/usr/bin/env perl
+    # å¯åŠ¨ euc-cn 字串解æž; 标准输出入åŠæ ‡å‡†é”™è¯¯éƒ½è®¾ä¸º euc-cn ç¼–ç 
+    use encoding 'euc-cn', STDIN => 'euc-cn', STDOUT => 'euc-cn';
+    print length("骆驼");      #  2 (åŒå¼•å·è¡¨ç¤ºå­—符)
+    print length('骆驼');      #  4 (å•å¼•å·è¡¨ç¤ºå­—节)
+    print index("谆谆教诲", "蛔唤"); # -1 (ä¸åŒ…å«æ­¤å­å­—符串)
+    print index('谆谆教诲', '蛔唤'); #  1 (从第二个字节开始)
+

在最åŽä¸€åˆ—例å­é‡Œ, "è°†" 的第二个字节与 "è°†" 的第一个字节结åˆæˆ EUC-CN ç çš„ "è›”"; "è°†" 的第二个字节则与 "æ•™" 的第一个字节结åˆæˆ "唤". è¿™è§£å†³äº†ä»¥å‰ EUC-CN ç æ¯”对处ç†ä¸Šå¸¸è§çš„问题.

+

额外的中文编ç 

+

如果需è¦æ›´å¤šçš„中文编ç , å¯ä»¥ä»Ž CPAN (http://www.cpan.org/) 下载 Encode::HanExtra 模å—. 它目å‰æ供下列编ç æ–¹å¼:

+
    gb18030     扩充过的国标ç , 包å«ç¹ä½“中文
+

另外, Encode::HanConvert 模å—则æ供了简ç¹è½¬æ¢ç”¨çš„两ç§ç¼–ç :

+
    big5-simp   Big5 ç¹ä½“中文与 Unicode 简体中文互转
+    gbk-trad    GBK 简体中文与 Unicode ç¹ä½“中文互转
+

若想在 GBK 与 Big5 之间互转, 请å‚考该模å—内附的 b2g.pl 与 g2b.pl 两支程åº, 或在程åºå†…使用下列写法:

+
    use Encode::HanConvert;
+    $euc_cn = big5_to_gb($big5); # 从 Big5 转为 GBK
+    $big5 = gb_to_big5($euc_cn); # 从 GBK 转为 Big5
+

进一步的信æ¯

+

请å‚考 Perl 内附的大é‡è¯´æ˜Žæ–‡ä»¶ (ä¸å¹¸å…¨æ˜¯ç”¨è‹±æ–‡å†™çš„), æ¥å­¦ä¹ æ›´å¤šå…³äºŽ Perl 的知识, ä»¥åŠ Unicode 的使用方å¼. ä¸è¿‡, 外部的资æºç›¸å½“丰富:

+

提ä¾› Perl 资æºçš„网å€

+
http://www.perl.com/

Perl 的首页 (由欧莱礼公å¸ç»´æŠ¤)

http://www.cpan.org/

Perl 综åˆå…¸è—网 (Comprehensive Perl Archive Network)

http://lists.perl.org/

Perl 邮递论å›ä¸€è§ˆ

+

学ä¹  Perl 的网å€

+
http://www.oreilly.com.cn/html/perl.html

简体中文版的欧莱礼 Perl 书藉

+

Perl 使用者集会

+
http://www.pm.org/groups/asia.shtml#China

中国 Perl 推广组一览

+

Unicode 相关网å€

+
http://www.unicode.org/

Unicode 学术学会 (Unicode 标准的制定者)

http://www.cl.cam.ac.uk/%7Emgk25/unicode.html

Unix/Linux 上的 UTF-8 åŠ Unicode 答客问

+

SEE ALSO

+

Encode, Encode::CN, encoding, perluniintro, perlunicode

+

AUTHORS

+

Jarkko Hietaniemi <jhi@iki.fi>

+

Autrijus Tang (å”宗汉) <autrijus@autrijus.org>

+ + diff --git a/POD/CN_html/perlembed.html b/POD/CN_html/perlembed.html new file mode 100644 index 0000000..8995f4f --- /dev/null +++ b/POD/CN_html/perlembed.html @@ -0,0 +1,714 @@ + + + + perlembed + + + + +

NAME

+

perlembed - 在 C 程åºä¸­åµŒå…¥ perl

+

DESCRIPTION

+

导言

+

你是想è¦ï¼š

+
在 Perl 中使用 C?

阅读 perlxstutperlxsh2xsperlguts å’Œ perlapi

在 Perl 中使用 Unix 程åºï¼Ÿ

阅读å引用符(back-quote)和 L <perlfunc> 中的 system ä»¥åŠ exec

在 Perl 中使用 Perl?

阅读 "do" in perlfunc"eval" in perlfunc"require" in perlfunc ä»¥åŠ "use" in perlfunc

在 C 中使用 C?

重新考虑一下你的设计。

在 C 中使用 Perl?

请继续……

+

路æ ‡

+
    +
  • 编译你的 C 程åº
  • +
  • 在ä½ çš„ C 程åºä¸­åŠ å…¥ä¸€ä¸ª Perl 解释器
  • +
  • 在 C 程åºä¸­è°ƒç”¨ä¸€ä¸ª Perl 函数
  • +
  • 在 C 程åºä¸­å¯¹ä¸€ä¸ª Perl 语å¥æ±‚值
  • +
  • 在 C 程åºä¸­è¿›è¡Œ Perl 模å¼åŒ¹é…和替æ¢
  • +
  • 在 C 程åºä¸­ä¿®æ”¹ Perl å‚æ•°æ ˆ
  • +
  • 保æŒä¸€ä¸ªæŒä¹…的解释器
  • +
  • 保æŒå¤šä¸ªè§£é‡Šå™¨å®žä¾‹
  • +
  • 在 C 程åºä¸­ä½¿ç”¨ Perl 模å—,模å—本身使用 C 库
  • +
  • 在 Win32 下内嵌 Perl
  • +
+

编译你的 C 程åº

+

你ä¸æ˜¯å”¯ä¸€ä¸€ä¸ªåœ¨ç¼–译本文档的例å­æ—¶é‡åˆ°å›°éš¾çš„。一个é‡è¦è§„则是:用编译你的 Perl 相åŒè§„则æ¥ç¼–译程åºï¼ˆå¯¹ä¸èµ·ï¼Œå¯¹ä½ å¤§å£°å–Šäº†ï¼‰ã€‚

+

每个使用 Perl çš„ C 程åºéƒ½å¿…须链接到 perl 库perl 库 是 什么?Perl 本身是用 C æ¥å†™çš„,perl library 是一系列编译过的 C 程åºï¼Œè¿™ 些将用于创建你的å¯æ‰§è¡Œ perl 程åºï¼ˆ/usr/bin/perl 或者等价的东西)。 ï¼ˆæŽ¨è®ºï¼šé™¤éž Perl 是在你的机器上编译的,或者åˆé€‚安装的,å¦åˆ™ä½ å°†ä¸èƒ½åœ¨ C 程åºä¸­ä½¿ç”¨ Perl——这也是为什么你ä¸åº”该从å¦ä¸€å°æœºå™¨ä¸­å¤åˆ¶ Perl çš„å¯æ‰§ 行程åºè€Œä¸å¤åˆ¶ lib 目录。)

+

当你在 C 中使用 Perl 时,你的 C 程åºå°†ï¼ˆé€šå¸¸æ˜¯è¿™æ ·ï¼‰åˆ†é…ã€è¿è¡Œç„¶åŽé‡Šæ”¾ 一个 PerlInterpreter 对象,这个对象是在 perl 库中定义的。

+

如果你的 Perl 足够新,包å«äº†æœ¬æ–‡æ¡£ï¼ˆç‰ˆæœ¬ 5.002 或者更新的),那么 perl 库(还有必须的 EXTERN.h å’Œ perl.h)将在看上去åƒè¿™æ ·çš„目录中:

+
    /usr/local/lib/perl5/your_architecture_here/CORE
+

或者å¯èƒ½å°±æ˜¯

+
    /usr/local/lib/perl5/CORE
+

或者å¯èƒ½åƒè¿™æ ·

+
    /usr/opt/perl5/CORE
+

执行这样的语å¥å¯ä»¥æ‰¾åˆ° CORE:

+
    perl -MConfig -e 'print $Config{archlib}'
+

这是在我的 Linux æœºå™¨ä¸Šç¼–è¯‘ä¸‹ä¸€èŠ‚ä¸­ä¾‹å­ "Adding a Perl interpreter to your C program" 的方法:

+
    % gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include
+    -I/usr/local/lib/perl5/i586-linux/5.003/CORE
+    -L/usr/local/lib/perl5/i586-linux/5.003/CORE
+    -o interp interp.c -lperl -lm
+

(就这一行。)在我的 DEC Alpha 使用旧的 5.003_05,这个“咒语â€æœ‰ä¸€ç‚¹ä¸åŒï¼š

+
    % cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include
+    -I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE
+    -L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib
+    -D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
+

怎样知é“应该加上什么呢?å‡å®šä½ çš„ Perl 中在 5.001 之åŽï¼Œæ‰§è¡Œ perl -V 命令,特别è¦æ³¨æ„“ccâ€å’Œâ€œccflagsâ€ä¿¡æ¯ã€‚

+

你必须选择åˆé€‚的编译器(ccgcc 等等)。在你的机器上:perl -MConfig -e 'print $Config{cc}' 将告诉你è¦ä½¿ç”¨ä»€ä¹ˆã€‚

+

你还è¦ä¸ºä½ çš„机器选择åˆé€‚的库目录(/usr/local/lib/...)。如果你的编 译器抱怨æŸä¸ªå‡½æ•°æ²¡æœ‰å®šä¹‰ï¼Œæˆ–者它找ä¸åˆ° -lperl,这时你需è¦æ›´æ”¹åœ¨ -L 之åŽçš„路径。如果它抱怨找ä¸åˆ° EXTERN.h å’Œ perl.h,你需è¦æ›´ 改在 -I 之åŽçš„路径。

+

你å¯èƒ½è¿˜è¦åŠ ä¸Šä¸€äº›é¢å¤–的库。加什么呢?å¯èƒ½æ˜¯ç”¨ä¸‹é¢è¯­å¥è¾“出的那些:

+
   perl -MConfig -e 'print $Config{libs}'
+

如果你的 perl 库é…置是适当的,已ç»å®‰è£…了 ExtUtils::Embed 模å—,它会 为你决定所有的这些信æ¯ï¼š

+
   % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+

如æžœ ExtUtils::Embed 模å—ä¸æ˜¯ä½ çš„ Perl å‘行版的一部分,你å¯ä»¥ä»Ž http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/ 获得。(如果本文档是æ¥è‡ªä½ çš„ Perl å‘行版,那你用的是 5.004 或者更好, 你就已ç»æœ‰è¿™ä¸ªæ¨¡å—了。)

+

CPAN 上 ExtUtils::Embed 套装也包å«æœ¬æ–‡æ¡£ä¾‹å­çš„所有æºä»£ç ï¼Œæµ‹è¯•ï¼Œé¢ 外的例å­ä»¥åŠå…¶å®ƒå¯èƒ½æœ‰ç”¨çš„ä¿¡æ¯ã€‚

+

在 C 程åºä¸­åŠ å…¥ Perl 解释器

+

在æŸç§æ„义上说,perl(这里指 C 程åºï¼‰æ˜¯ä¸€ä¸ªå†…嵌 Perl(这里指语言)的一 个很好的例å­ã€‚所以我将用包å«åœ¨å‘行版æºæ–‡ä»¶ä¸­çš„ miniperlmain.c æ¥æ¼” 示。这是一个拙劣的ã€ä¸å¯ç§»æ¤çš„ miniperlmain.c 版本,但是包å«äº†å†…嵌 的本质:

+
    #include <EXTERN.h>               /* from the Perl distribution     */
+    #include <perl.h>                 /* from the Perl distribution     */
+
+    static PerlInterpreter *my_perl;  /***    The Perl interpreter    ***/
+
+    int main(int argc, char **argv, char **env)
+    {
+        PERL_SYS_INIT3(&argc,&argv,&env);
+        my_perl = perl_alloc();
+        perl_construct(my_perl);
+        PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+        perl_parse(my_perl, NULL, argc, argv, (char **)NULL);
+        perl_run(my_perl);
+        perl_destruct(my_perl);
+        perl_free(my_perl);
+        PERL_SYS_TERM();
+    }
+

注æ„,我们没有用到 env 指针。通常åªæ˜¯ä½œä¸º perl_parse 的最åŽä¸€ä¸ª å‚æ•°æ供给它。这里 env 用 NULL 代替了,表示使用当å‰çš„环境。 PERL_SYS_INIT3() å’Œ PERL_SYS_TERM() å®ä¸º Perl 解释器的è¿è¡Œæä¾›äº†å¿…è¦ çš„ã€ç³»ç»Ÿç‰¹å®šçš„ C è¿è¡ŒçŽ¯å¢ƒã€‚由于 PERL_SYS_INIT3() å¯èƒ½ä¿®æ”¹ env,所 有最好æä¾› perl_parse() 一个 env å‚数。

+

现在编译æˆå¯æ‰§è¡Œç¨‹åºï¼ˆæˆ‘称之为 interp.c):

+
    % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+

在æˆåŠŸç¼–译åŽï¼Œä½ å°±å¯ä»¥ç”¨ interp å°±åƒ perl 本身一样:

+
    % interp
+    print "Pretty Good Perl \n";
+    print "10890 - 9801 is ", 10890 - 9801;
+    <CTRL-D>
+    Pretty Good Perl
+    10890 - 9801 is 1089
+

或者

+
    % interp -e 'printf("%x", 3735928559)'
+    deadbeef
+

可以在你的 C 程åºä¸­è¯»å…¥å’Œæ‰§è¡Œ Perl 语å¥ï¼Œåªéœ€è¦åœ¨è°ƒç”¨ perl_run å‰æ”¾ 置文件å在 argv[1] 中。

+

在 C 程åºä¸­è°ƒç”¨ Perl 函数

+

要调用å•ä¸ª Perl 函数,你å¯ä»¥ä½¿ç”¨ä»»ä½•ä¸€ä¸ªåœ¨ perlcall 中介ç»çš„ call_* 函数。 在这个例å­ä¸­ï¼Œæˆ‘们使用 all_argv

+

下é¢æ˜¾ç¤ºä¸€ä¸ªæˆ‘称为 showtime.c 的程åºï¼š

+
    #include <EXTERN.h>
+    #include <perl.h>
+
+    static PerlInterpreter *my_perl;
+
+    int main(int argc, char **argv, char **env)
+    {
+        char *args[] = { NULL };
+        PERL_SYS_INIT3(&argc,&argv,&env);
+        my_perl = perl_alloc();
+        perl_construct(my_perl);
+
+        perl_parse(my_perl, NULL, argc, argv, NULL);
+        PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+
+        /*** skipping perl_run() ***/
+
+        call_argv("showtime", G_DISCARD | G_NOARGS, args);
+
+        perl_destruct(my_perl);
+        perl_free(my_perl);
+        PERL_SYS_TERM();
+    }
+

这里 showtime 是一个没有å‚æ•°çš„ Perl 函数(就是 G_NOARGS),而且 忽略一返回值(就是 G_DISCARD)。在 perlcall 中有讨论这些以åŠå…¶å®ƒ 标签。

+

我在一个称为 showtime.pl 文件中定义这个 showtime 函数:

+
    print "I shan't be printed.";
+
+    sub showtime {
+        print time;
+    }
+

很简å•ã€‚现在编译并è¿è¡Œï¼š

+
    % cc -o showtime showtime.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+
+    % showtime showtime.pl
+    818284590
+

产生从 1970 å¹´ 1 月 1 日(Unix çºªå…ƒçš„å¼€å§‹ï¼‰åˆ°çŽ°åœ¨çš„ç§’æ•°ï¼Œè¿™æ˜¯æˆ‘å†™è¿™å¥ è¯çš„时间。

+

在这个特殊例å­ä¸­ï¼Œæˆ‘们ä¸å¿…调用 perl_run,因为我们设置了 PL_exit_flag PERL_EXIT_DESTRUCT_END,这将在 perl_destruct 中执行 END å—。

+

如果你想è¦ä¼ é€’å‚æ•°ç»™ Perl 函数,你å¯ä»¥åœ¨ä»¥ NULL 结尾的 args 列表 中加入字符串传递给 call_argv。对于其它数æ®ç±»åž‹ï¼Œæˆ–者è¦æ£€æŸ¥è¿”回值类 型,你需è¦æ“作 Perl å‚数栈。在 "Fiddling with the Perl stack from your C program" 中演示了这个过程。

+

在 C 程åºä¸­å¯¹ Perl 语å¥æ±‚值

+

Perl æ供两个 API 函数æ¥å¯¹ä¸€å°æ®µ Perl 代ç è¿›è¡Œæ±‚值。这就是 "eval_sv" in perlapi å’Œ "eval_pv" in perlapi

+

在 C 程åºä¸­åªæœ‰è¿™ä¸¤ä¸ªå‡½æ•°ï¼Œä½ å¯ä»¥æ‰§è¡Œä¸€æ®µ Perl 代ç ã€‚你的代ç å¯ä»¥ä»»æ„ 长,å¯ä»¥åŒ…å«å¤šä¸ªè¯­å¥ï¼Œä½ å¯ä»¥ç”¨ "use" in perlfunc"require" in perlfunc、 å’Œ "do" in perlfunc æ¥å¼•å…¥ä¸€ä¸ª Perl 文件。

+

eval_pv å¯ä»¥å¯¹å•ä¸ªçš„ Perl 字符串求值,然åŽå¯ä»¥æå–出å˜é‡è½¬æ¢ä¸º C ç±» 型。下é¢è¿™ä¸ªç¨‹åº string.c 执行三个 Perl 字符串,第一个æå–出一个 int å˜é‡ï¼Œç¬¬äºŒä¸ªæå– float å˜é‡ï¼Œç¬¬ä¸‰ä¸ªæå– char * å˜é‡ã€‚

+
   #include <EXTERN.h>
+   #include <perl.h>
+
+   static PerlInterpreter *my_perl;
+
+   main (int argc, char **argv, char **env)
+   {
+       STRLEN n_a;
+       char *embedding[] = { "", "-e", "0" };
+
+       PERL_SYS_INIT3(&argc,&argv,&env);
+       my_perl = perl_alloc();
+       perl_construct( my_perl );
+
+       perl_parse(my_perl, NULL, 3, embedding, NULL);
+       PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+       perl_run(my_perl);
+
+       /** Treat $a as an integer **/
+       eval_pv("$a = 3; $a **= 2", TRUE);
+       printf("a = %d\n", SvIV(get_sv("a", FALSE)));
+
+       /** Treat $a as a float **/
+       eval_pv("$a = 3.14; $a **= 2", TRUE);
+       printf("a = %f\n", SvNV(get_sv("a", FALSE)));
+
+       /** Treat $a as a string **/
+       eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);", TRUE);
+       printf("a = %s\n", SvPV(get_sv("a", FALSE), n_a));
+
+       perl_destruct(my_perl);
+       perl_free(my_perl);
+       PERL_SYS_TERM();
+   }
+

所有在å字中å«æœ‰ sv 的奇怪函数都是为了å助将 Perl æ ‡é‡è½¬æ¢ä¸º C 类型。 这在 perlguts å’Œ perlapi 中有æ述。

+

如果你编译并è¿è¡Œ string.c,ä½ å¯ä»¥ç”¨ SvIV() 创建一个 intSvNV() 创建一个 floatSvPV() åˆ›å»ºä¸€ä¸ªå­—ç¬¦ä¸²ï¼Œè¿™æ ·å¯ ä»¥çœ‹åˆ°ç»“æžœã€‚

+
   a = 9
+   a = 9.859600
+   a = Just Another Perl Hacker
+

在上é¢çš„例å­ä¸­ï¼Œæˆ‘们创建了一个全局å˜é‡æ¥ä¸´æ—¶ä¿å­˜æ±‚值åŽè®¡ç®—çš„ç»“æžœã€‚ä¹Ÿå¯ ä»¥ï¼Œå¹¶åœ¨å¤§å¤šæ•°æƒ…å†µä¸‹æœ€å¥½ç”¨ eval_pv() 的返回值。例如:

+
   ...
+   STRLEN n_a;
+   SV *val = eval_pv("reverse 'rekcaH lreP rehtonA tsuJ'", TRUE);
+   printf("%s\n", SvPV(val,n_a));
+   ...
+

这æ ·ä¸ç”¨åˆ›å»ºä¸€ä¸ªå…¨å±€å˜é‡ï¼Œå¯ä»¥é¿å…污染å字空间,也åŒæ ·ä½¿ä»£ç ç®€åŒ–。

+

在 C 程åºä¸­è¿›è¡Œ Perl 模å¼åŒ¹é…和替æ¢

+

eval_sv() 函数å¯ä»¥å¯¹ Perl 代ç å­—符串求值,所以我们å¯ä»¥å®šä¹‰ä¸€äº›å‡½æ•° 专门进行匹é…和替æ¢ï¼šmatch()substitute() å’Œ matches()

+
   I32 match(SV *string, char *pattern);
+

假定有一个字符串和一个模å¼ï¼ˆä¾‹å¦‚ m/clasp/ 或者 /\b\w*\b/,在你的 C 程åºä¸­å¯èƒ½æ˜¯è¿™æ ·çš„ "/\\b\\w*\\b/")。如果字符串匹é…一个模å¼åˆ™è¿”回 1,å¦åˆ™è¿”回 0。

+
   int substitute(SV **string, char *pattern);
+

假å®šæœ‰ä¸€ä¸ªæŒ‡å‘ SV 的指针和 =~ æ“作符(例如 s/bob/robert/g 或 者 tr[A-Z][a-z]),substitute() æ ¹æ®è¿™ä¸ªæ“作符修改 SV,è¿”å›žæ›¿æ¢ æ“作的次数。

+
   int matches(SV *string, char *pattern, AV **matches);
+

假定有一个 SV,一个模å¼å’Œä¸€ä¸ªæŒ‡å‘一个空 AV 的指针,match() 在一 个列表上下文中对 $string =~ $pattern 求值,在 matches 中填充数 组,返回匹é…的数目。

+

这是一个使用了三个函数的样例,match.c(过长的行折å äº†ï¼‰ï¼š

+
 #include <EXTERN.h>
+ #include <perl.h>
+
+ static PerlInterpreter *my_perl;
+
+ /** my_eval_sv(code, error_check)
+ ** kinda like eval_sv(), 
+ ** but we pop the return value off the stack 
+ **/
+ SV* my_eval_sv(SV *sv, I32 croak_on_error)
+ {
+     dSP;
+     SV* retval;
+     STRLEN n_a;
+
+     PUSHMARK(SP);
+     eval_sv(sv, G_SCALAR);
+
+     SPAGAIN;
+     retval = POPs;
+     PUTBACK;
+
+     if (croak_on_error && SvTRUE(ERRSV))
+        croak(SvPVx(ERRSV, n_a));
+
+     return retval;
+ }
+
+ /** match(string, pattern)
+ **
+ ** Used for matches in a scalar context.
+ **
+ ** Returns 1 if the match was successful; 0 otherwise.
+ **/
+
+ I32 match(SV *string, char *pattern)
+ {
+     SV *command = NEWSV(1099, 0), *retval;
+     STRLEN n_a;
+
+     sv_setpvf(command, "my $string = '%s'; $string =~ %s",
+              SvPV(string,n_a), pattern);
+
+     retval = my_eval_sv(command, TRUE);
+     SvREFCNT_dec(command);
+
+     return SvIV(retval);
+ }
+
+ /** substitute(string, pattern)
+ **
+ ** Used for =~ operations that modify their left-hand side (s/// and tr///)
+ **
+ ** Returns the number of successful matches, and
+ ** modifies the input string if there were any.
+ **/
+
+ I32 substitute(SV **string, char *pattern)
+ {
+     SV *command = NEWSV(1099, 0), *retval;
+     STRLEN n_a;
+
+     sv_setpvf(command, "$string = '%s'; ($string =~ %s)",
+              SvPV(*string,n_a), pattern);
+
+     retval = my_eval_sv(command, TRUE);
+     SvREFCNT_dec(command);
+
+     *string = get_sv("string", FALSE);
+     return SvIV(retval);
+ }
+
+ /** matches(string, pattern, matches)
+ **
+ ** Used for matches in a list context.
+ **
+ ** Returns the number of matches,
+ ** and fills in **matches with the matching substrings
+ **/
+
+ I32 matches(SV *string, char *pattern, AV **match_list)
+ {
+     SV *command = NEWSV(1099, 0);
+     I32 num_matches;
+     STRLEN n_a;
+
+     sv_setpvf(command, "my $string = '%s'; @array = ($string =~ %s)",
+              SvPV(string,n_a), pattern);
+
+     my_eval_sv(command, TRUE);
+     SvREFCNT_dec(command);
+
+     *match_list = get_av("array", FALSE);
+     num_matches = av_len(*match_list) + 1; /** assume $[ is 0 **/
+
+     return num_matches;
+ }
+
+ main (int argc, char **argv, char **env)
+ {
+     char *embedding[] = { "", "-e", "0" };
+     AV *match_list;
+     I32 num_matches, i;
+     SV *text;
+     STRLEN n_a;
+
+     PERL_SYS_INIT3(&argc,&argv,&env);
+     my_perl = perl_alloc();
+     perl_construct(my_perl);
+     perl_parse(my_perl, NULL, 3, embedding, NULL);
+     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+
+     text = NEWSV(1099,0);
+     sv_setpv(text, "When he is at a convenience store and the "
+        "bill comes to some amount like 76 cents, Maynard is "
+        "aware that there is something he *should* do, something "
+        "that will enable him to get back a quarter, but he has "
+        "no idea *what*.  He fumbles through his red squeezey "
+        "changepurse and gives the boy three extra pennies with "
+        "his dollar, hoping that he might luck into the correct "
+        "amount.  The boy gives him back two of his own pennies "
+        "and then the big shiny quarter that is his prize. "
+        "-RICHH");
+
+     if (match(text, "m/quarter/")) /** Does text contain 'quarter'? **/
+        printf("match: Text contains the word 'quarter'.\n\n");
+     else
+        printf("match: Text doesn't contain the word 'quarter'.\n\n");
+
+     if (match(text, "m/eighth/")) /** Does text contain 'eighth'? **/
+        printf("match: Text contains the word 'eighth'.\n\n");
+     else
+        printf("match: Text doesn't contain the word 'eighth'.\n\n");
+
+     /** Match all occurrences of /wi../ **/
+     num_matches = matches(text, "m/(wi..)/g", &match_list);
+     printf("matches: m/(wi..)/g found %d matches...\n", num_matches);
+
+     for (i = 0; i < num_matches; i++)
+        printf("match: %s\n", SvPV(*av_fetch(match_list, i, FALSE),n_a));
+     printf("\n");
+
+     /** Remove all vowels from text **/
+     num_matches = substitute(&text, "s/[aeiou]//gi");
+     if (num_matches) {
+        printf("substitute: s/[aeiou]//gi...%d substitutions made.\n",
+               num_matches);
+        printf("Now text is: %s\n\n", SvPV(text,n_a));
+     }
+
+     /** Attempt a substitution **/
+     if (!substitute(&text, "s/Perl/C/")) {
+        printf("substitute: s/Perl/C...No substitution made.\n\n");
+     }
+
+     SvREFCNT_dec(text);
+     PL_perl_destruct_level = 1;
+     perl_destruct(my_perl);
+     perl_free(my_perl);
+     PERL_SYS_TERM();
+ }
+

它产生这样的输出(过长的行å†æ¬¡æŠ˜å äº†ï¼‰ï¼š

+
   match: Text contains the word 'quarter'.
+
+   match: Text doesn't contain the word 'eighth'.
+
+   matches: m/(wi..)/g found 2 matches...
+   match: will
+   match: with
+
+   substitute: s/[aeiou]//gi...139 substitutions made.
+   Now text is: Whn h s t  cnvnnc str nd th bll cms t sm mnt lk 76 cnts,
+   Mynrd s wr tht thr s smthng h *shld* d, smthng tht wll nbl hm t gt bck
+   qrtr, bt h hs n d *wht*.  H fmbls thrgh hs rd sqzy chngprs nd gvs th by
+   thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct mnt.  Th by gvs
+   hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s hs prz. -RCHH
+
+   substitute: s/Perl/C...No substitution made.
+

在 C 程åºä¸­å¡«å…… Perl å‚æ•°æ ˆ

+

大多数计算机教科书对于栈的解释都是é‡å¤å…³äºŽæ”¾ç½®å’–啡盘的比喻(most computer science textbooks mumble something about spring-loaded columns of cafeteria plates):最åŽä½ æ”¾åˆ°æ ˆä¸­çš„东西就是你第一个å–出的。 这是我们的è¦åšçš„:C 程åºæ”¾ç½®ä¸€äº›å‚数到“Perl æ ˆâ€ä¸­ï¼Œå½“魔术å‘生时闭上它的 眼ç›ï¼Œç„¶åŽä»Žæ ˆä¸Šå–出结果——Perl 函数的返回值(That'll do for our purposes: your C program will push some arguments onto "the Perl stack", shut its eyes while some magic happens, and then pop the results--the return value of your Perl subroutine--off the stack.)

+

首先,你è¦çŸ¥é“怎样在 C 类型和 Perl 类型之间转æ¢ï¼Œä½¿ç”¨ newSViv()〠sv_setnvã€newAV() 以åŠå…¶å®ƒå®ƒä»¬çš„朋å‹ã€‚它们在 perlguts å’Œ perlapi 中有说明。

+

然åŽä½ è¦çŸ¥é“如何æ“纵 Perl å‚数栈。在 perlcall 中有说明。

+

一旦你明白这些,在 C 中嵌入 Perl 是很简å•çš„。

+

因为 C 没有内建的函数进行整数的指数è¿ç®—,让我们用 Perl çš„ ** è¿ç®—符实 现它(这比它å¬ä¸ŠåŽ»æ²¡ç”¨å¾—多,因为 Perl 用 C pow() 函数实现 **)。首 先在 power.pl 中创建一个简短的指数函数:

+
    sub expo {
+        my ($a, $b) = @_;
+        return $a ** $b;
+    }
+

现在我创建一个 C ç¨‹åº power.c,通过 PerlPower() (包å«æ‰€æœ‰å¿…须的 perlguts)将两个å‚数放到expo() 并å–出返回值。深å¸ä¸€å£æ°”:

+
    #include <EXTERN.h>
+    #include <perl.h>
+
+    static PerlInterpreter *my_perl;
+
+    static void
+    PerlPower(int a, int b)
+    {
+      dSP;                            /* initialize stack pointer      */
+      ENTER;                          /* everything created after here */
+      SAVETMPS;                       /* ...is a temporary variable.   */
+      PUSHMARK(SP);                   /* remember the stack pointer    */
+      XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack  */
+      XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack  */
+      PUTBACK;                      /* make local stack pointer global */
+      call_pv("expo", G_SCALAR);      /* call the function             */
+      SPAGAIN;                        /* refresh stack pointer         */
+                                    /* pop the return value from stack */
+      printf ("%d to the %dth power is %d.\n", a, b, POPi);
+      PUTBACK;
+      FREETMPS;                       /* free that return value        */
+      LEAVE;                       /* ...and the XPUSHed "mortal" args.*/
+    }
+
+    int main (int argc, char **argv, char **env)
+    {
+      char *my_argv[] = { "", "power.pl" };
+
+      PERL_SYS_INIT3(&argc,&argv,&env);
+      my_perl = perl_alloc();
+      perl_construct( my_perl );
+
+      perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL);
+      PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+      perl_run(my_perl);
+
+      PerlPower(3, 4);                      /*** Compute 3 ** 4 ***/
+
+      perl_destruct(my_perl);
+      perl_free(my_perl);
+      PERL_SYS_TERM();
+    }
+

编译并è¿è¡Œï¼š

+
    % cc -o power power.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+
+    % power
+    3 to the 4th power is 81.
+

保æŒä¸€ä¸ªæŒä¹…的解释器

+

当å¼€å‘一个交互而且(或者)å¯èƒ½æ˜¯æŒä¹…è¿è¡Œçš„应用程åºï¼Œä¸è¦å¤šæ¬¡åˆ†é…构建新 的解释器,ä¿æŒä¸€ä¸ªæŒä¹…的解释器是一个好主æ„。最主è¦çš„原因是速度:因为 Perl åªè¦å¯¼å…¥åˆ°å†…存中一次。

+

尽管这样,当使用一个æŒä¹…的解释器时è¦ç‰¹åˆ«å°å¿ƒå字空间和å˜é‡ä½œç”¨åŸŸã€‚åœ¨å‰ é¢çš„例å­ä¸­ï¼Œæˆ‘们在默认的包 main 中使用全局å˜é‡ã€‚我们很清楚地知é“代 ç æ˜¯æ€Žæ ·è¿è¡Œçš„,并且å‡å®šæˆ‘们能够é¿å…å˜é‡å†²çªå’Œç¬¦å·è¡¨çš„增长。

+

假定你的应用程åºæ˜¯ä¸€ä¸ªæœåŠ¡å™¨ï¼Œå®ƒå¶å°”è¿è¡Œä¸€äº›æ–‡ä»¶ä¸­çš„ Perl 代ç ã€‚ä½ çš„æœ åŠ¡å™¨æ˜¯ä¸çŸ¥é“è¦è¿è¡Œä»€ä¹ˆä»£ç çš„。这很å±é™©ã€‚

+

如果文件用 perl_parse() 引入的,编译æˆä¸€ä¸ªæ–°åˆ›å»ºçš„解释器,然åŽæŽ¥ç€ 用 perl_destruct() 作一次清ç†ï¼Œè¿™æ ·å°±å¯ä»¥å±è”½äº†å¤§å¤šæ•°çš„å字空间的问 题。

+

一个é¿å…å字空间冲çªçš„方法是将文件å转æ¢æˆä¸€ä¸ªå”¯ä¸€çš„包å,然åŽç”¨ "eval" in perlfunc 将这段代ç ç¼–译到这个包中。在下é¢çš„例å­ä¸­ï¼Œæ¯ä¸ªæ–‡ä»¶åª 编译一次。或者这个应用程åºåœ¨ä¸€ä¸ªæ–‡ä»¶ä¸­çš„符å·è¡¨ä¸å†éœ€è¦æ—¶å¯èƒ½ä¼šæ¸…除这个 符å·è¡¨ã€‚使用 "call_argv" in perlapi,我们调用在 persistent.pl 文件中 çš„ Embed::Persistent::eval_file,传递一个文件å以åŠä¸€ä¸ªæ¸…除或者缓冲 的标签作为å‚数。

+

注æ„到对于æ¯ä¸ªä½¿ç”¨çš„文件,这个进程都è¦ä¸æ–­å¢žé•¿ã€‚å¦å¤–,å¯èƒ½æœ‰ AUTOLOAD 函数或者其它æ¡ä»¶å¯¼è‡´ Perl 符å·è¡¨çš„增长。你å¯èƒ½æƒ³åŠ å…¥ä¸€äº›é€» 辑判断æ¥è·Ÿè¸ªè¿›ç¨‹çš„大å°ï¼Œæˆ–者在一定次数的请求之åŽé‡æ–°å¯åŠ¨ä¸€æ¬¡ï¼Œè¿™æ ·æ¥ä¿è¯å†… 存的消耗是ä¿è¯æœ€å°çš„。你å¯èƒ½è¿˜ä¼šåœ¨å¯èƒ½çš„时候用 "my" in perlfunc é™å®šå˜é‡çš„范围。

+
 package Embed::Persistent;
+ #persistent.pl
+
+ use strict;
+ our %Cache;
+ use Symbol qw(delete_package);
+
+ sub valid_package_name {
+     my($string) = @_;
+     $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
+     # second pass only for words starting with a digit
+     $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
+
+     # Dress it up as a real package name
+     $string =~ s|/|::|g;
+     return "Embed" . $string;
+ }
+
+ sub eval_file {
+     my($filename, $delete) = @_;
+     my $package = valid_package_name($filename);
+     my $mtime = -M $filename;
+     if(defined $Cache{$package}{mtime}
+        &&
+        $Cache{$package}{mtime} <= $mtime)
+     {
+        # we have compiled this subroutine already,
+        # it has not been updated on disk, nothing left to do
+        print STDERR "already compiled $package->handler\n";
+     }
+     else {
+        local *FH;
+        open FH, $filename or die "open '$filename' $!";
+        local($/) = undef;
+        my $sub = <FH>;
+        close FH;
+
+        #wrap the code into a subroutine inside our unique package
+        my $eval = qq{package $package; sub handler { $sub; }};
+        {
+            # hide our variables within this block
+            my($filename,$mtime,$package,$sub);
+            eval $eval;
+        }
+        die $@ if $@;
+
+        #cache it unless we're cleaning out each time
+        $Cache{$package}{mtime} = $mtime unless $delete;
+     }
+
+     eval {$package->handler;};
+     die $@ if $@;
+
+     delete_package($package) if $delete;
+
+     #take a look if you want
+     #print Devel::Symdump->rnew($package)->as_string, $/;
+ }
+
+ 1;
+
+ __END__
+
+ /* persistent.c */
+ #include <EXTERN.h>
+ #include <perl.h>
+
+ /* 1 = clean out filename's symbol table after each request, 0 = don't */
+ #ifndef DO_CLEAN
+ #define DO_CLEAN 0
+ #endif
+
+ #define BUFFER_SIZE 1024
+
+ static PerlInterpreter *my_perl = NULL;
+
+ int
+ main(int argc, char **argv, char **env)
+ {
+     char *embedding[] = { "", "persistent.pl" };
+     char *args[] = { "", DO_CLEAN, NULL };
+     char filename[BUFFER_SIZE];
+     int exitstatus = 0;
+     STRLEN n_a;
+
+     PERL_SYS_INIT3(&argc,&argv,&env);
+     if((my_perl = perl_alloc()) == NULL) {
+        fprintf(stderr, "no memory!");
+        exit(1);
+     }
+     perl_construct(my_perl);
+
+     exitstatus = perl_parse(my_perl, NULL, 2, embedding, NULL);
+     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+     if(!exitstatus) {
+        exitstatus = perl_run(my_perl);
+
+        while(printf("Enter file name: ") &&
+              fgets(filename, BUFFER_SIZE, stdin)) {
+
+            filename[strlen(filename)-1] = '\0'; /* strip \n */
+            /* call the subroutine, passing it the filename as an argument */
+            args[0] = filename;
+            call_argv("Embed::Persistent::eval_file",
+                           G_DISCARD | G_EVAL, args);
+
+            /* check $@ */
+            if(SvTRUE(ERRSV))
+                fprintf(stderr, "eval error: %s\n", SvPV(ERRSV,n_a));
+        }
+     }
+
+     PL_perl_destruct_level = 0;
+     perl_destruct(my_perl);
+     perl_free(my_perl);
+     PERL_SYS_TERM();
+     exit(exitstatus);
+ }
+

Now compile:

+
 % cc -o persistent persistent.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+

Here's an example script file:

+
 #test.pl
+ my $string = "hello";
+ foo($string);
+
+ sub foo {
+     print "foo says: @_\n";
+ }
+

Now run:

+
 % persistent
+ Enter file name: test.pl
+ foo says: hello
+ Enter file name: test.pl
+ already compiled Embed::test_2epl->handler
+ foo says: hello
+ Enter file name: ^C
+

执è¡Œ END å—

+

传统的 END å—在 perl_run 的结æŸæ—¶æ‰§è¡Œäº†ã€‚对于ä¸è°ƒç”¨ perl_run 的应用程 åºè¿™ä¼šæœ‰ä¸€äº›é—®é¢˜ã€‚从 perl 5.7.2 开始,你å¯ä»¥æŒ‡å®š PL_exit_flags |= PERL_EXIT_DESTRUCT_END æ¥èŽ·å¾—新特性。这也å¯ä»¥åœ¨ perl_parse 失败之åŽè°ƒ 用 END å—,perl_destruct 将返回退出值。

+

保æŒå¤šä¸ªè§£é‡Šå™¨çš„实例

+

一些罕è§çš„应用程åºåœ¨ä¸€æ¬¡å¯¹è¯ä¸­éœ€è¦åˆ›å»ºå¤šä¸ªè§£é‡Šå™¨ã€‚å¯èƒ½è¦å¶ç„¶é‡Šæ”¾è§£é‡Šå™¨ 对应的资æºã€‚

+

这个程åºè¦ç¡®ä¿è¦åœ¨ä¸‹ä¸€ä¸ªè§£é‡Šå™¨å°±åšè¿™äº›äº‹ã€‚默认情况下,当 perl ä¸ç”¨ä»»ä½• 选项构建时,全局å˜é‡ PL_perl_destruct_level 设置为 0。因为在一个程 åºç”Ÿå­˜æœŸä¸­åªåˆ›å»ºä¸€ä¸ªè§£é‡Šå™¨æ˜¯ä¸éœ€è¦è¿›è¡Œé¢å¤–的清ç†ã€‚

+

PL_perl_destruct_level 设置为 1 å¯ä»¥ä½¿æ‰€æœ‰çš„都清除了:

+
 while(1) {
+     ...
+     /* reset global variables here with PL_perl_destruct_level = 1 */
+     PL_perl_destruct_level = 1;
+     perl_construct(my_perl);
+     ...
+     /* clean and reset _everything_ during perl_destruct */
+     PL_perl_destruct_level = 1;
+     perl_destruct(my_perl);
+     perl_free(my_perl);
+     ...
+     /* let's go do it again! */
+ }
+

perl_destruct() 调用时,这个解释器的语法解æžæ ‘和符å·è¡¨å°±è¢«æ¸…除, 全局å˜é‡ä¹Ÿè¢«é‡æ–°è®¾ç½®ã€‚因为 perl_construct 会将 PL_perl_destruct_level é‡æ–°è®¾ç½®ä¸º 0,所以è¦å†ä¸€æ¬¡è®¾ç½® PL_perl_destruct_level

+

现在å‡å®šæˆ‘们åŒæ—¶æœ‰å¤šä¸ªè§£é‡Šå™¨è¿è¡Œã€‚这是å¯ä»¥åšåˆ°çš„,但是åªæœ‰åœ¨ä½ åˆ›å»º perl 时使用é…置选项 -Dusemultiplicity 或者 -Dusethreads -Duseithreads。缺çœæƒ…况下,打开这些é…置选项中的一个就把这个 per-interpreter 全局å˜é‡ PL_perl_destruct_level 设置为 1ã€‚æ‰€ä»¥æ¸…ç† æ˜¯è‡ªåŠ¨çš„ï¼Œå¹¶ä¸”è§£é‡Šå™¨å˜é‡å˜æ­£ç¡®çš„åˆå§‹åŒ–。å³ä½¿ä½ ä¸ç”¨åŒæ—¶è¿è¡Œå¤šä¸ªè§£é‡Šå™¨ï¼Œ 而是è¦åƒå‰é¢çš„例å­é‚£æ ·é¡ºåºè¿è¡Œï¼Œä½†è¿˜æ˜¯å»ºè®®ä½ ç”¨ -Dusemultiplicity 选项æ¥ç¼–译 perl。å¦åˆ™ä¸€äº›è§£é‡Šå™¨çš„å˜é‡åœ¨è¿žç»­è¿è¡Œè¿‡ç¨‹ä¸­ä¸ä¼šæ­£ç¡®çš„åˆå§‹åŒ–,你 çš„è¿è¡Œç¨‹åºå¯èƒ½ä¼šå´©æºƒã€‚

+

如果你打算在ä¸åŒçº¿ç¨‹ä¸­å¹¶å‘è¿è¡Œå¤šä¸ªè§£é‡Šå™¨æ—¶ï¼Œä½¿ç”¨ -Dusethreads -Duseithreads 而ä¸æ˜¯-Dusemultiplicity å¯èƒ½æ›´åˆé€‚。因为这å¯ä»¥å¯¹è§£é‡Š 器支æŒé“¾æŽ¥åˆ°ç³»ç»Ÿçš„线程库。

+

让我们æ¥è¯•ä¸€ä¸‹ï¼š

+
 #include <EXTERN.h> #include <perl.h>
+
+ /* we're going to embed two interpreters */
+ /* we're going to embed two interpreters */
+
+ #define SAY_HELLO "-e", "print qq(Hi, I'm $^X\n)"
+
+ int main(int argc, char **argv, char **env)
+ {
+     PerlInterpreter *one_perl, *two_perl;
+     char *one_args[] = { "one_perl", SAY_HELLO };
+     char *two_args[] = { "two_perl", SAY_HELLO };
+
+     PERL_SYS_INIT3(&argc,&argv,&env);
+     one_perl = perl_alloc();
+     two_perl = perl_alloc();
+
+     PERL_SET_CONTEXT(one_perl);
+     perl_construct(one_perl);
+     PERL_SET_CONTEXT(two_perl);
+     perl_construct(two_perl);
+
+     PERL_SET_CONTEXT(one_perl);
+     perl_parse(one_perl, NULL, 3, one_args, (char **)NULL);
+     PERL_SET_CONTEXT(two_perl);
+     perl_parse(two_perl, NULL, 3, two_args, (char **)NULL);
+
+     PERL_SET_CONTEXT(one_perl);
+     perl_run(one_perl);
+     PERL_SET_CONTEXT(two_perl);
+     perl_run(two_perl);
+
+     PERL_SET_CONTEXT(one_perl);
+     perl_destruct(one_perl);
+     PERL_SET_CONTEXT(two_perl);
+     perl_destruct(two_perl);
+
+     PERL_SET_CONTEXT(one_perl);
+     perl_free(one_perl);
+     PERL_SET_CONTEXT(two_perl);
+     perl_free(two_perl);
+     PERL_SYS_TERM();
+ }
+

注æ„ PERL_SET_CONTEXT() 的调用。这对于全局状æ€çš„åˆå§‹åŒ–中必须的( These are necessary to initialize the global state that tracks which interpreter is the "current" one on the particular process or thread that may be running it.)如果你有多个解释器并且åŒæ—¶å¯¹è¿™äº›è§£é‡Šå™¨äº¤å‰è°ƒ 用 perl API,就应该总是使用它。

+

interp 在一个ä¸æ˜¯åˆ›å»ºå®ƒçš„线程(使用 perl_alloc() 或者更深奥 çš„ perl_clone())使用时,也应该调用 PERL_SET_CONTEXT(interp)。

+

像通常那样编译:

+
 % cc -o multiplicity multiplicity.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+

赶å¿«è¿è¡Œå§ï¼š

+
 % multiplicity
+ Hi, I'm one_perl
+ Hi, I'm two_perl
+

在ä½ çš„ C 程åºä¸­ä½¿ç”¨ Perl 模å—,这些模å—本身也使用 C 库

+

如果你在使用上é¢çš„例å­ä¸­è¯•å›¾åµŒå…¥ä¸€ä¸ªè„šæœ¬ï¼Œè¿™ä¸ªè„šæœ¬è°ƒç”¨ä¸€ä¸ªä½¿ç”¨ C 或者 C++ 库的 Perl 模å—(例如 Socket),å¯èƒ½ä¼šå‘生:

+
 Can't load module Socket, dynamic loading not available in this perl.
+  (You may need to build a new perl executable which either supports
+  dynamic loading or has the Socket module statically linked into it.)
+

出什么错了?

+

你的解释器ä¸çŸ¥é“怎样与这些扩展交æµã€‚一个å°å°çš„粘åˆä»£ç å°†ä¼šèµ·åˆ°ä½œç”¨ã€‚ç›´ 到现在你还是用 NULL 作为第二个å‚数调用 perl_parse()

+
 perl_parse(my_perl, NULL, argc, my_argv, NULL);
+

这是使用粘åˆä»£ç çš„地方,它在 Perl 和链接的 C/C++ 函数创建起始的连接。 让我们看看在 perlmain.c 中的一段看看 Perl 是怎样åšçš„:

+
 static void xs_init (pTHX);
+
+ EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
+ EXTERN_C void boot_Socket (pTHX_ CV* cv);
+
+
+ EXTERN_C void
+ xs_init(pTHX)
+ {
+        char *file = __FILE__;
+        /* DynaLoader is a special case */
+        newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+        newXS("Socket::bootstrap", boot_Socket, file);
+ }
+

对于æ¯ä¸ªè¦é“¾æŽ¥åˆ°ä½ çš„ Perl å¯æ‰§è¡Œç¨‹åºçš„扩展(由你电脑的åˆå§‹åŒ–é…置决定或 者当加入一个新的扩展),创建一个 Perl 函数整åˆæ‰©å±•ä¸­çš„函数。通常这个函 æ•°å« Module::boostrap(),当你使用 use Module 就调用了这个函数。 In turn, this hooks into an XSUB, boot_Module, which creates a Perl counterpart for each of the extension's XSUBs. Don't worry about this part; leave that to the xsubpp and extension authors. If your extension is dynamically loaded, DynaLoader creates Module::bootstrap() for you on the fly. In fact, if you have a working DynaLoader then there is rarely any need to link in any other extensions statically.

+

一旦你有这段代ç ï¼ŒæŠŠå®ƒåŠ åˆ° perl_parse() 的第二个å‚数中:

+
 perl_parse(my_perl, xs_init, argc, my_argv, NULL);
+

然åŽç¼–译:

+
 % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
+
+ % interp
+   use Socket;
+   use SomeDynamicallyLoadedModule;
+
+   print "Now I can use extensions!\n"'
+

ExtUtils::Embed 也能自动写 xs_init 粘åˆä»£ç ï¼š

+
 % perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
+ % cc -c perlxsi.c `perl -MExtUtils::Embed -e ccopts`
+ % cc -c interp.c  `perl -MExtUtils::Embed -e ccopts`
+ % cc -o interp perlxsi.o interp.o `perl -MExtUtils::Embed -e ldopts`
+

详细内容å‚考 perlxsperlguts å’Œ perlapi

+

在 Win32 嵌入 Perl

+

一般,这里显示的所有代ç åœ¨ Windows 下ä¸ç”¨ä»»ä½•ä¿®æ”¹å°±èƒ½å·¥ä½œã€‚

+

尽管这样,这里有一些命令行例å­çš„警告。对于åˆå­¦è€…,在 Win32 本身的命令 行中是ä¸èƒ½ä½¿ç”¨å引å·çš„。在 CPAN çš„ ExtUtils::Embed 中有一个称为 genmake 脚本。这å¯ä»¥ä»Žå•ä¸ªçš„ C æºæ–‡ä»¶ä¸­åˆ›å»ºä¸€ä¸ªç®€å•çš„ makefileã€‚å¯ ä»¥è¿™æ ·ä½¿ç”¨ï¼š

+
 C:\ExtUtils-Embed\eg> perl genmake interp.c
+ C:\ExtUtils-Embed\eg> nmake
+ C:\ExtUtils-Embed\eg> interp -e "print qq{I'm embedded in Win32!\n}"
+

你å¯èƒ½æƒ³åœ¨ Microsoft Developer Studio 中使用更稳å¥çš„环境( You may wish to use a more robust environment such as the Microsoft Developer Studio.)。在这ç§æƒ…况下中,用这个æ¥äº§ç”Ÿ perlxsi.c:

+
 perl -MExtUtils::Embed -e xsinit
+

创å»ºä¸€ä¸ªæ–°çš„å·¥ç¨‹ï¼Œç„¶åŽ Insert -> Files 到工程中:perlxsi.c,perl.lib, 和你自己的æºæ–‡ä»¶ï¼Œä¾‹å¦‚ interp.c。一般你å¯ä»¥åœ¨ C:\perl\lib\CORE 中找 到 perl.lib。如果没有的è¯ï¼Œä½ å¯ä»¥ç”¨ perl -V:archlib 中找到 CORE 目录。studio 还è¦çŸ¥é“在哪里找到 Perl çš„ include 文件。这个路径å¯ä»¥é€šè¿‡ Tools -> Options -> Directories èœå•æ¥åŠ å…¥ã€‚最åŽï¼Œé€‰æ‹© Build -> Build interp.exe,这样就好了。

+

隐è— Perl_

+

在编译标签中加入 -DPERL_NO_SHORT_NAMES,你就å¯ä»¥éšè— Perl 公共接å£çš„简短 å½¢å¼ã€‚è¿™æ„味ç€ä½ ä¸èƒ½è¿™æ ·å†™ï¼š

+
    warn("%d bottles of beer on the wall", bottlecount);
+

你必须写明确完全的形å¼ï¼š

+
    Perl_warn(aTHX_ "%d bottles of beer on the wall", bottlecount);
+

(å‚考 "Background and PERL_IMPLICIT_CONTEXT for the explanation of the aTHX_." in perlguts)éšè—简短的形å¼å¯¹äºŽé¿å…和其它软件包的冲çªï¼ˆC é¢„å¤„ç† æˆ–è€…å…¶å®ƒï¼‰ã€‚ï¼ˆPerl 用简短å字定义了 2400 API,所以很有å¯èƒ½å‘生冲çªã€‚)

+

MORAL

+

有æ—¶å¯ä»¥åœ¨ C 中写出 运行更快的代ç ï¼ˆwrite faster code),但是你总是å¯ä»¥åœ¨ Perl 中更快地写出代ç ï¼ˆwrite code faster)。因为你å¯ä»¥ç›¸äº’ä½¿ç”¨å¯¹æ–¹ï¼Œåª è¦ä½ éœ€è¦å¯ä»¥ç»“åˆèµ·æ¥ã€‚

+

AUTHOR

+

Jon Orwant <orwant@media.mit.edu> and Doug MacEachern <dougm@covalent.net>, with small contributions from Tim Bunce, Tom Christiansen, Guy Decoux, Hallvard Furuseth, Dov Grobgeld, and Ilya Zakharevich.

+

Doug MacEachern has an article on embedding in Volume 1, Issue 4 of The Perl Journal ( http://www.tpj.com/ ). Doug is also the developer of the most widely-used Perl embedding: the mod_perl system (perl.apache.org), which embeds Perl in the Apache web server. Oracle, Binary Evolution, ActiveState, and Ben Sugars's nsapi_perl have used this model for Oracle, Netscape and Internet Information Server Perl plugins.

+

July 22, 1998

+

COPYRIGHT

+

Copyright (C) 1995, 1996, 1997, 1998 Doug MacEachern and Jon Orwant. All Rights Reserved.

+

Permission is granted to make and distribute verbatim copies of this documentation provided the copyright notice and this permission notice are preserved on all copies.

+

Permission is granted to copy and distribute modified versions of this documentation under the conditions for verbatim copying, provided also that they are marked clearly as modified versions, that the authors' names and title are unchanged (though subtitles and additional authors' names may be added), and that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

+

Permission is granted to copy and distribute translations of this documentation into another language, under the above conditions for modified versions.

+

TRANSLATORS

+

YE Wenbin

+ + diff --git a/POD/CN_html/perlintro.html b/POD/CN_html/perlintro.html new file mode 100644 index 0000000..87eccd5 --- /dev/null +++ b/POD/CN_html/perlintro.html @@ -0,0 +1,370 @@ + + + + perlintro + + + + +

NAME

+

perlintro -- Perl简介和概览

+

DESCRIPTION

+

该文档将为您æä¾›Perl编程语言的快速概览,并指导您阅读其他更深入的文档。 对于刚刚接触Perl的人,它å¯ä»¥è¢«å½“作一份"入门"å‘导。它æ供刚刚好的信æ¯ï¼Œ 使你能够阅读别人的Perl代ç å¹¶ç²—略知é“这些代ç åœ¨åšä»€ä¹ˆï¼Œä»¥åŠèƒ½å¤Ÿè‡ªå·±ç¼–å†™ç®€å• çš„è„šæœ¬ã€‚

+

这份介ç»æ€§çš„文档并ä¸æ‰“算覆盖全é¢ã€‚它甚至ä¸æ‰“算写的éžå¸¸ç²¾ç¡®ã€‚有时为了抓ä½é‡ç‚¹ï¼Œ 我们必须牺牲完美。强烈建议您看完本介ç»ä»¥åŽç»§ç»­é˜…读整个Perl手册获å–更多的信æ¯ã€‚ Perl手册的目录å‚è§perltoc

+

在本文档中你会到处看到对Perl文档的其他部分的引用。你å¯ä»¥ä½¿ç”¨ä½ çŽ°åœ¨æ­£ç”¨æ¥é˜…读 本文档的方法或perldoc指令去阅读那些文档。

+

Perl是什么?

+

Perl是一门常规用途的语言。最åˆè¢«å¼€å‘出æ¥ç”¨äºŽæ–‡æœ¬å¤„ç†ï¼ˆç»´æŠ¤ï¼‰ã€‚现在被用于系统 管ç†ã€webå¼€å‘ã€ç½‘络编程ã€å›¾å½¢ç”¨æˆ·ç•Œé¢(GUI)å¼€å‘以åŠæ›´å¤šå…¶ä»–ç­‰å„ç§ä»»åŠ¡ã€‚

+

这门语言被设计得实用(容易使用ã€é«˜æ•ˆã€å®Œæ•´)胜于美观(å¾®å°ã€æ–‡é›…ã€ç®€åŒ–)。它的 主è¦ç‰¹ç‚¹æ˜¯å®¹æ˜“使用,支æŒé¢å‘过程编程和é¢å‘对象编程,内建强大的文本处ç†èƒ½åŠ›ï¼Œ 以åŠæ‹¥æœ‰ä¸–界上最著å的第三方模å—集åˆã€‚

+

perlperlfaq1和其他地方给出了关于Perlçš„ä¸åŒå®šä¹‰ã€‚从而我们å¯ä»¥çœ‹å‡ºPerl 对于ä¸åŒçš„人æ„味ç€ä¸åŒçš„东西,但至少他们都愿æ„把它记述下æ¥ã€‚

+

运è¡ŒPerl程åº

+

从Unix命令行è¿è¡ŒPerl程åºï¼š

+
    perl progname.pl
+

或者把下é¢çš„代ç å†™åˆ°ä½ è„šæœ¬çš„第一行:

+
    #!/usr/bin/env perl
+

... 然åŽè¿è¡Œ/path/to/script.pl。当然,该脚本必须具有执行æƒé™ï¼Œä½¿ç”¨ chmod 755 script.pl改å˜æƒé™(Unix下)。

+

更多信æ¯ï¼ŒåŒ…括其他平å°(如Windowså’ŒMac OS)的说明,请阅读perlrun

+

基本语法概览

+

一个Perl脚本/程åºç”±ä¸€æ¡æˆ–多æ¡è¯­å¥ç»„æˆã€‚这些语å¥ç›´æŽ¥å†™åœ¨è„šæœ¬é‡Œï¼Œè€Œä¸æ˜¯éœ€è¦å†™ 在什么main()或者类似的东西里。

+

perl语å¥ä»¥åˆ†å·(;)结尾:

+
    print "Hello, world";
+

注释使用井å·(#)开始,作用直到该行末尾

+
    # 这是一个注释
+

空白是无关紧è¦çš„:

+
    print 
+        "Hello, world"
+        ;
+

... 除éžæ˜¯åœ¨è¢«å¼•èµ·æ¥çš„字符串里:

+
    # 下é¢çš„打å°ä¸­é—´ä¼šæœ‰ä¸€ä¸ªæ¢è¡Œç¬¦
+    print "Hello
+    world";
+

可以使用åŒå¼•å·æˆ–å•å¼•å·åŒ…围文字串:

+
    print "Hello, world";
+    print 'Hello, world';
+

然而,åªæœ‰åŒå¼•å·å¯ä»¥"内æ’"å˜é‡å’Œç‰¹æ®Šå­—符,如æ¢è¡Œ(\n):

+
    print "Hello, $name\n";     # 内æ’å˜é‡å’Œæ¢è¡Œ
+    print 'Hello, $name\n';     # 打å°å‡ºå­—é¢çš„$name\n
+

数å­—ä¸éœ€è¦ç”¨å¼•å·å¼•èµ·ï¼š

+
    print 42;
+

你å¯ä»¥æ ¹æ®ä½ çš„喜好选择把函数å‚数用括å·æ‹¬èµ·æ¥ï¼Œæˆ–者忽略括å·ã€‚括å·åªæœ‰åœ¨å¶å°”用于 é˜æ˜Žä¼˜å…ˆçº§é—®é¢˜çš„时候æ‰è¢«éœ€è¦ã€‚

+
    print("Hello, world\n");
+    print "Hello, world\n";
+

关于Perl语法的详细信æ¯è¯·å‚阅perlsyn

+

Perlå˜é‡ç±»åž‹

+

Perl有三ç§å˜é‡ç±»åž‹ï¼šæ ‡é‡(scalar)ã€æ•°ç»„(array)ã€æ•£åˆ—(hash)。

+
+
标é‡(scalar)
+
+

一个标é‡è¡¨ç¤ºä¸€ä¸ªå•ä¸€çš„值:

+
    my $animal = "camel";
+    my $answer = 42;
+

标é‡å¯ä»¥æ˜¯å­—符串ã€æ•´æ•°æˆ–浮点数。在需è¦çš„时候,Perlå¯ä»¥è‡ªåŠ¨å¯¹å®ƒä»¬è¿›è¡Œç›¸äº’转æ¢ã€‚ ä¸éœ€è¦é¢„先声明å˜é‡ç±»åž‹ã€‚

+

标é‡çš„使用å¯ä»¥æœ‰å‡ ç§æ–¹å¼ï¼š

+
    print $animal;
+    print "The animal is $animal\n";
+    print "The square of $answer is ", $answer * $answer, "\n";
+

有许多看起æ¥åƒæ ‡ç‚¹ç¬¦å·æˆ–行噪音(line noise)çš„"魔力"æ ‡é‡ã€‚这些特殊的标é‡è¢«ç”¨äºŽ å„ç§ç”¨é€”,å‚考perlvar。现在你唯一需è¦çŸ¥é“的是$_,å³"缺çœå˜é‡"。它被用 作Perl中许多函数的缺çœå‚数,å¦å¤–æŸäº›å¾ªçŽ¯ç»“构会éšå«åœ°è®¾ç½®å®ƒçš„值。

+
    print;          # 缺çœä¼šæ‰“å°å‡º$_的内容
+
+
数组
+
+

一个数组表示一系列值(一些值的列表):

+
    my @animals = ("camel", "llama", "owl");
+    my @numbers = (23, 42, 69);
+    my @mixed   = ("camel", 42, 1.23);
+

数组下标从0开始。下é¢å±•ç¤ºäº†å¦‚何从数组中获å–元素:

+
    print $animals[0];              # prints "camel"
+    print $animals[1];              # prints "llama"
+

特殊å˜é‡$#array能告诉你一个数组的最åŽä¸€ä¸ªå…ƒç´ çš„下标:

+
    print $mixed[$#mixed];       # 最åŽä¸€ä¸ªå…ƒç´ ï¼Œè¾“出1.23
+

你å¯èƒ½ä¼šè¢«å¼•è¯±ä½¿ç”¨$#array + 1来获å–数组中元素的个数。别烦æ¼ã€‚å†æœ‰è¿™ç§éœ€è¦ 的时候,在Perl期待标é‡å€¼çš„地方("在标é‡ä¸Šä¸‹æ–‡ä¸­")使用@array就能得到数组中元 素的个数:

+
    if (@animals < 5) { ... }
+

我们从数组中获å–元素是以$打头,这是因为我们从数组中å–出的仅仅是一个å•ä¸€çš„ 值 -- 你请求一个标é‡ï¼Œä½ å¾—到一个标é‡ã€‚

+

要从数组中å–得多个值:

+
    @animals[0,1];                  # 得到 ("camel", "llama");
+    @animals[0..2];                 # 得到 ("camel", "llama", "owl");
+    @animals[1..$#animals];         # 得到除第一个之外的所有元素
+

这å«åš"数组切片"。

+

你å¯ä»¥å¯¹åˆ—表åšå„ç§æœ‰ç”¨çš„事:

+
    my @sorted    = sort @animals;
+    my @backwards = reverse @numbers;
+

同样,也存在也些特殊的数组,比如@ARGV(脚本的命令行å‚æ•°)å’Œ@_(传递给å­ä¾‹ç¨‹ çš„å‚æ•°)。这些都在perlvar中有详细文档。

+
+
散列
+
+

一个散列表示一套"é”®/值"对:

+
    my %fruit_color = ("apple", "red", "banana", "yellow");
+

你å¯ä»¥ç”¨ç©ºç™½å’Œ=>操作符把它们摆放的漂亮些:

+
    my %fruit_color = (
+        apple  => "red",
+        banana => "yellow",
+    );
+

要获å–一个散列元素:

+
    $fruit_color{"apple"};           # 得到 "red"
+

你å¯ä»¥åˆ†åˆ«ä½¿ç”¨keys()values()获å–散列的键列表和值列表。

+
    my @fruits = keys %fruit_colors;
+    my @colors = values %fruit_colors;
+

散列没有特定的内部顺åºï¼Œå°½ç®¡ä½ å¯ä»¥æŽ’列所有的键并é历它们。

+

就åƒç‰¹æ®Šæ ‡é‡å’Œç‰¹æ®Šæ•°ç»„,Perl里也有特殊散列。这其中最著å的是%ENV。它包å«ç€ 所有环境å˜é‡ã€‚关于这个(和其他特殊å˜é‡)请阅读perlvar

+
+
+

变é‡ã€æ•°ç»„和散列的更多文档请è§perldata

+

更å¤æ‚çš„æ•°æ®ç±»åž‹ä½¿ç”¨å¼•ç”¨æž„造,å¯ä»¥ä½¿ä½ åˆ›å»ºåˆ—表和散列的列表和散列。

+

一个引用是一个标é‡å€¼ã€‚它å¯ä»¥æŒ‡å‘(引用)任何其他数æ®ç±»åž‹(的值)。这样,通过存储 一个对数组或散列的引用,你å¯ä»¥è½»æ˜“地创建列表和散列的列表和散列。

+
    my $variables = {
+        scalar  =>  { 
+                     description => "single item",
+                     sigil => '$',
+                    },
+        array   =>  {
+                     description => "ordered list of items",
+                     sigil => '@',
+                    },
+        hash    =>  {
+                     description => "key/value pairs",
+                     sigil => '%',
+                    },
+    };
+
+    print "Scalars begin with a $variables->{'scalar'}->{'sigil'}\n";
+

关于引用这个主题的详细信æ¯å¯ä»¥å‚è§perlreftutperllolperlrefperldsc

+

变é‡ä½œç”¨åŸŸ

+

贯穿之å‰ç« èŠ‚的所有例å­ï¼Œéƒ½ä½¿ç”¨äº†è¿™æ ·çš„语法:

+
    my $var = "value";
+

my实际上ä¸æ˜¯å¿…须的;你å¯ä»¥ä»…仅使用这样的语法:

+
    $var = "value";
+

然åŽï¼Œä¸Šé¢è¿™ç§ç”¨æ³•ä¼šåˆ›å»ºè´¯ç©¿ä½ ç¨‹åºçš„全局å˜é‡ã€‚这是一个ä¸å¥½çš„编程习惯。而my 创建的是è¯æ³•å˜é‡ã€‚è¿™ç§å˜é‡çš„作用域会局é™äºŽå®šä¹‰å®ƒçš„å—(也就是一套包围在大括 å·({})里的语å¥)里。

+
    my $a = "foo";
+    if ($some_condition) {
+        my $b = "bar";
+        print $a;           # 输出 "foo"
+        print $b;           # 输出 "bar"
+    }
+    print $a;               # 输出 "foo"
+    print $b;               # 什么都ä¸è¾“出;$bå·²ç»è¶…出了作用域
+

配åˆä½¿ç”¨my和Perl脚本顶部的use strict;,æ„味ç€è§£é‡Šå™¨å°†æ£€æŸ¥æŸäº›å¸¸è§çš„编程 错误。举例æ¥è¯´ï¼Œåœ¨ä¸Šé¢çš„例å­é‡Œï¼Œæœ€åŽçš„print $b会产生一个编译时错误并阻止你 è¿è¡Œç¨‹åºã€‚强烈推è使用strict

+

条件和循环结构

+

Perl拥有几乎所有常è§çš„æ¡ä»¶å’Œå¾ªçŽ¯ç»“构,除了case/switch(但å‡å¦‚你实在想è¦ï¼Œ Perl 5.8åŠä»¥ä¸Šçš„版本或CPAN里有一个Switch模å—。关于模å—å’ŒCPAN,请看åŽé¢å…³äºŽæ¨¡ å—的章节)。

+

条件å¯ä»¥æ˜¯ä»»ä½•Perl表达å¼ã€‚å‚看下一节中关于比较和布尔逻辑æ“作符的列表。它们在 æ¡ä»¶è¯­å¥é‡Œå¾ˆå¸¸ç”¨ã€‚

+
+
if
+
+
    if ( condition ) {
+        ...
+    } elsif ( other condition ) {
+        ...
+    } else {
+        ...
+    }
+

if还有一个å¦å®šç‰ˆæœ¬ï¼š

+
    unless ( condition ) {
+        ...
+    }
+

这ç­‰åŒäºŽif (!condition),但是一个更易读的版本。

+

注æ„在Perl里括å·æ˜¯å¿…须的,就算å—里åªæœ‰ä¸€è¡Œã€‚然而,有一个èªæ˜Žçš„方法å¯ä»¥è®©ä½ çš„ å•è¡Œè¯­å¥å—看起æ¥æ›´åƒè‹±è¯­ï¼š

+
    # 传统方å¼
+    if ($zippy) {
+        print "Yow!";
+    }
+
+    # Perlishå‰ç½®æ–¹å¼
+    print "Yow!" if $zippy;
+    print "We have no bananas" unless $bananas;
+
+
while
+
+
    while ( condition ) {
+        ...
+    }
+

基于åŒæ ·çš„原因,也有一个å¦å®šç‰ˆæœ¬ -- unless

+
    until ( condition ) {
+        ...
+    }
+

你也å¯ä»¥ä½¿ç”¨æ¡ä»¶åŽç½®çš„while

+
    print "LA LA LA\n" while 1;          # 永远循环
+
+
for
+
+

跟C一模一样:

+
    for ($i=0; $i <= $max; $i++) {
+        ...
+    }
+

在Perl里很少需è¦ç”¨åˆ°Cæ ·å¼çš„循环,因为Perlæ供了更å‹å–„的列表é历方法 -- foreach循环。

+
+
foreach
+
+
    foreach (@array) {
+        print "This element is $_\n";
+    }
+
+    # ä½ ä¸ä¸€å®šéžå¾—使用缺çœçš„$_...
+    foreach my $key (keys %hash) {
+        print "The value of $key is $hash{$key}\n";
+    }
+
+
+

关于循环结构(以åŠä¸€äº›è¿™ç¯‡æ¦‚览里没有æ到的结构)的更多细节,请å‚è§perlsyn

+

内建æ“作符和函数

+

Perl自带了一大套内建函数。有一些我们已ç»è§è¯†è¿‡äº†ï¼šprintsortreverseperlfunc的开始处有内建函数的完整列表。å¦å¤–ä½ å¯ä»¥å¾ˆæ–¹ä¾¿åœ°ä½¿ç”¨ perldoc -f functionname查看æŸä¸ªç»™å®šå‡½æ•°ã€‚

+

Perlæ“作符详细记述于perlop。ä¸è¿‡è¿™é‡Œæˆ‘们先看看一些最常用的:

+
+
算术
+
+
    +   加
+    -   å‡
+    *   乘
+    /   除
+
+
数字比较
+
+
    ==  相等
+    !=  ä¸ç­‰
+    <   å°äºŽ
+    >   大于
+    <=  å°ç­‰äºŽ
+    >=  大等于
+
+
字符串比较
+
+
    eq  相等
+    ne  ä¸ç­‰
+    lt  å°äºŽ
+    gt  大于
+    le  å°ç­‰äºŽ
+    ge  大等于
+

(为什么我们è¦åˆ†ç¦»æ•°å­—和字符串比较?因为我们没有指定的å˜é‡ç±»åž‹ï¼Œè€Œperl需è¦çŸ¥é“ 我们是è¦æŒ‰æ•°å­—排åº(99应该å°äºŽ100),还是按字符排åº(100应该在99å‰é¢)。

+
+
布尔逻辑
+
+
    &&  and
+    ||  or
+    !   not
+

(andornot不仅仅是在上表中作为æ“作符的æè¿° -- 它们也是享有Perl支 æŒçš„æ“作符。它们比Cæ ·å¼çš„æ“作符更易读,但是与&&及其他å‹ç¬¦å…·æœ‰ä¸åŒçš„有é™çº§ã€‚ 查看perlop以获å–更多细节。)

+
+
其ä»–
+
+
    =   赋值
+    .   字符串比较
+    x   字符串乘
+    ..  范围æ“作符(创建数字的列表)
+
+
+

许多æ“作符å¯ä»¥å’Œ=结åˆä½¿ç”¨ï¼Œåƒä¸‹é¢è¿™æ ·ï¼š

+
    $a += 1;        # same as $a = $a + 1
+    $a -= 1;        # same as $a = $a - 1
+    $a .= "\n";     # same as $a = $a . "\n";
+

文件和I/O

+

你å¯ä»¥ä½¿ç”¨open()函数打开一个文件用于输入或输出。在perlfuncperlopentut中有详细得近乎奢侈的文档。简而言之:

+
    open(INFILE,  "input.txt")   or die "Can't open input.txt: $!";
+    open(OUTFILE, ">output.txt") or die "Can't open output.txt: $!";
+    open(LOGFILE, ">>my.log")    or die "Can't open logfile: $!";
+

使用<>操作符,你å¯ä»¥ä»Žä¸€ä¸ªå·²æ‰“开的文件å¥æŸ„中读å–æ•°æ®ã€‚在标é‡ä¸Šä¸‹æ–‡ä¸­ï¼Œ 它æ¯æ¬¡ä»Žæ–‡ä»¶å¥æŸ„中读å–一行。在列表上下文中,它会一次读入整个文件,并把æ¯ä¸€è¡Œ 赋给列表的一个元素:

+
    my $line  = <INFILE>;
+    my @lines = <INFILE>;
+

一次读入整个文件也å«åšå•œé£Ÿ(sluping)。有时候会有用,ä¸è¿‡å¾ˆè€—å†…å­˜ã€‚å¤šæ•°çš„æ–‡æœ¬å¤„ç† å·¥ä½œå¯ä»¥ä½¿ç”¨Perl的循环结构一次一行地进行。

+

<>操作符最常è§äºŽwhile循环:

+
    while (<INFILE>) {     # æ¯è¡Œè½®æµèµ‹ç»™$_ 
+        print "Just read in this line: $_";
+    }
+

我们已ç»è§è¿‡å¦‚何å‘æ ‡å‡†è¾“å‡ºæ‰“å° -- 使用print()。然而,print()还有一个å¯é€‰ 的第一个å‚数,用于指定输出用的文件å¥æŸ„:

+
    print STDERR "This is your final warning.\n";
+    print OUTFILE $record;
+    print LOGFILE $logmessage;
+

当你进行完所有对文件å¥æŸ„çš„æ“作åŽï¼Œä½ åº”该close()它们(虽然è€å®žåœ°è¯´ï¼Œå¦‚果你忘 了,Perl会替你清ç†):

+
    close INFILE;
+

正则表达å¼

+

Perl对正则表达å¼çš„支æŒæ˜¯å¹¿æ³›è€Œæ·±å…¥çš„。perlrequickperlretut及其他地方的 冗长文档都是关于这个主题的。尽管如此,简而言之:

+
+
简å•åŒ¹é…
+
+
    if (/foo/)       { ... }  # 当$_包å«"foo"时为真
+    if ($a =~ /foo/) { ... }  # 当$a包å«"foo"时为真
+

匹é…æ“作符//perlop中有文档记述。它缺çœå¯¹$_进è¡Œæ“作,或者å¯ä»¥é€šè¿‡ä½¿ç”¨ 绑定æ“作符=~(也在perlop中有记述)绑定到其他å˜é‡ã€‚

+
+
简å•æ›¿æ¢
+
+
    s/foo/bar/;               # 把$_中的foo替æ¢æˆbar
+    $a =~ s/foo/bar/;         # 把$a中的foo替æ¢æˆbar
+    $a =~ s/foo/bar/g;        # 把$a中的所有foo都替æ¢æˆbar
+

替æ¢æ“作符s///记述于perlop中。

+
+
更å¤æ‚的正则表达å¼
+
+

你ä¸å¿…仅仅匹é…固定的字符串。实际上,通过使用å¤æ‚的正则表达å¼ï¼Œä½ å¯ä»¥åŒ¹é…梦想的 任何东西。这些都记述在超长的perlre文档里。但是è¶è¿™ä¼šå„¿ï¼Œå…ˆçœ‹çœ‹å¿«é€Ÿä½œå¼Šå¡ï¼š

+
    .                   å•ä¸ªå­—符
+    \s                  空白字符(空格ã€åˆ¶è¡¨ç¬¦(tab)ã€æ¢è¡Œ)
+    \S                  éžç©ºç™½å­—符
+    \d                  一个阿拉伯数字(0-9)
+    \D                  一个éž(阿拉伯)æ•°å­—
+    \w                  一个å•è¯(word)字符(a-zã€A-Zã€0-9ã€_)
+    \W                  一个éžå•è¯å­—符
+    [aeiou]             匹é…给定集åˆä¸­çš„å•ä¸ªå­—符
+    [^aeiou]            匹é…给定集åˆä¹‹å¤–çš„å•ä¸ªå­—符
+    (foo|bar|baz)       匹é…指定选择中的任何一个
+
+    ^                   字符串开始
+    $                   字符串结尾
+

限é‡ç¬¦(quantifier)å¯ä»¥ç”¨æ¥æŒ‡å®šå®ƒå‰é¢çš„东西匹é…的次数。这里"东西"指的å¯ä»¥æ˜¯ 一个文字的字符,或者上é¢åˆ—出的这些元字符中的一个,也å¯ä»¥æ˜¯æ‹¬åœ¨æ‹¬å·ä¸­çš„一组 字符和元字符。

+
    *                   0次或多次
+    +                   1次或多次
+    ?                   0次或1次
+    {3}                 匹é…3次
+    {3,6}               匹é…3到6次
+    {3,}                匹é…3次或更多
+

一些简è¦çš„例å­ï¼š

+
    /^\d+/              以一个或多个阿拉伯数字开头的字符串
+    /^$/                空字符串(开始ä½ç½®å’Œç»“æŸä½ç½®è¿žåœ¨ä¸€èµ·)
+    /(\d\s){3}/         三个阿拉伯数字,æ¯ä¸ªæ•°å­—åŽé¢æœ‰ä¸ªç©ºç™½å­—符(如:"3 4 5 ") 
+    /(a.)+/             匹é…一个字符串,它的æ¯ä¸ªç¬¬å¥‡æ•°ä¸ªå­—符都是a
+                        (如:"abacadaf") 
+
+    # 下é¢è¿™ä¸ªå¾ªçŽ¯ä»Žæ ‡å‡†è¾“å…¥(STDIN)读入,然åŽè¾“出æ¯ä¸€ä¸ªéžç©ºçš„行:
+    while (<>) {
+        print;
+    }
+
+
用于æ•æ‰çš„括å·
+
+

除了分组,括å·è¿˜æœ‰ç¬¬äºŒä¸ªä½œç”¨ã€‚它们å¯ä»¥è¢«ç”¨æ¥æ•æ‰æ­£åˆ™åŒ¹é…çš„æŸäº›éƒ¨åˆ†çš„结果以备 åŽç”¨ã€‚结果被ä¿å­˜åœ¨$1$2依此类推等å˜é‡é‡Œã€‚

+
    # 一个简å•è€Œè‚®è„çš„æ–¹å¼æ¥æŠŠemail地å€æ‹†æˆå‡ éƒ¨åˆ†
+
+    if ($email =~ /([^@]+)@(.+)/) {
+        print "Username is $1\n";
+        print "Hostname is $2\n";
+    }
+
+
其他正则表达å¼ç‰¹æ€§
+

Perl正则还支æŒå‘åŽå¼•ç”¨(backreference)ã€å‰çž»(lookahead)以åŠå„ç§å…¶ä»–å¤æ‚的细节。 这些全都能从perlrequickperlretutperlre中读到。

+
+

编写å­ä¾‹ç¨‹

+

编写å­ä¾‹ç¨‹å¾ˆå®¹æ˜“:

+
    sub log {
+        my $logmessage = shift;
+        print LOGFILE $logmessage;
+    }
+

那个shift是什么?好的,传递给å­ä¾‹ç¨‹çš„å‚数都存储在一个å«@_的特殊数组里(å‚ é˜…perlvar)。而shift函数的缺çœå‚数正好是@_。因而 my $logmessage = shift;会移出å‚数列表的第一个元素并把它赋给$logmessage

+

我们也å¯ä»¥ç”¨å…¶ä»–æ–¹å¼æ¥æ“作@_

+
    my ($logmessage, $priority) = @_;       # 常用
+    my $logmessage = $_[0];                 # ä¸å¸¸ç”¨ï¼Œè€Œä¸”丑陋
+

子例程å¯ä»¥è¿”回值:

+
    sub square {
+        my $num = shift;
+        my $result = $num * $num;
+        return $result;
+    }
+

关于编写å­ä¾‹ç¨‹çš„更多信æ¯ï¼Œå‚è§perlsub

+

面å‘对象(OO)Perl

+

面å‘对象Perl相对简å•ï¼Œæ˜¯ç”¨å¼•ç”¨å®žçŽ°çš„。这些引用知é“它们自己是哪ç§å¯¹è±¡(基于Perl 中的包的概念)。然åŽï¼Œé¢å‘对象Perl严é‡è¶…出了本文档的讨论范围。请阅读perlbootperltootperltoocperlobj

+

作为Perlåˆçº§ç¨‹åºå‘˜ï¼Œä½ ç”¨åˆ°é¢å‘对象Perl最多是在使用第三方模å—的时候,下é¢çš„文档 就会讲到。

+

使用Perl模å—

+

Perl模å—æ供一系列的特性以使你é¿å…é‡å¤å‘明轮å­ã€‚Perl模å—å¯ä»¥ä»ŽCPAN ( http:www.cpan.org/ )下载。大é‡çš„常用的模å—被直接包å«åœ¨Perlå‘行版里。

+

模å—类别从文本维护到网络å议到数æ®åº“集æˆï¼Œå†åˆ°å›¾å½¢å›¾åƒï¼Œåº”有尽有。模å—的分类 列表也å¯ä»¥åœ¨CPAN上找到。

+

要学习如何安装你从CPAN上下载的模å—,阅读perlmodinstall

+

要学习如何使用一个特定的模å—,使用perldoc Module::Name。一般æ¥è¯´ï¼Œä½ ä¼šéœ€è¦ use Module::Name。这会使你éšåŽèƒ½å¤Ÿè®¿é—®å¯¼å‡ºçš„函数或者该模å—的一个é¢å‘对象 接å£ã€‚

+

perlfaq里有关于å„ç§å¸¸è§ä»»åŠ¡çš„æ问和答案,而且常常会建议你使用一些优秀CPAN模 å—。

+

perlmod提ä¾›Perl模å—çš„å…¨é¢æ¦‚è¦ã€‚perlmodlib列出了所有你安装的Perl自带的 模å—。

+

如果你有编写Perl模å—的冲动,perlnewmod会给你很好的建议。

+

AUTHOR

+

Kirrily "Skud" Robert <skud@cpan.org>

+

Translated by Achilles Xu <formalin14@gmail.com>

+ + diff --git a/POD/CN_html/perllol.html b/POD/CN_html/perllol.html new file mode 100644 index 0000000..302386f --- /dev/null +++ b/POD/CN_html/perllol.html @@ -0,0 +1,188 @@ + + + + perllol + + + + +

NAME

+

perllol - æ“作数组的数组(二维数组)

+

说明

+

声明和访问数组的数组

+

创建一个数组的数组(有时也å¯ä»¥å«â€œåˆ—表的列表â€ï¼Œä¸è¿‡ä¸å¤ªå‡†ç¡®ï¼‰çœŸæ˜¯å†ç®€ å•ä¹Ÿä¸è¿‡äº†ã€‚它相当容易ç†è§£ï¼Œå¹¶ä¸”本文中出现的æ¯ä¸ªä¾‹å­éƒ½æœ‰å¯èƒ½åœ¨å®žé™…应用 中出现。

+

数组的数组就是一个普通的数组(@AoA),ä¸è¿‡å¯ä»¥æŽ¥å—两个下标($AoA[3][2])。 下é¢å…ˆå®šä¹‰ä¸€ä¸ªè¿™æ ·çš„数组:

+
    # 一个包å«æœ‰â€œæŒ‡å‘数组的引用â€çš„数组
+    @AoA = (
+        [ "fred", "barney" ],
+        [ "george", "jane", "elroy" ],
+        [ "homer", "marge", "bart" ],
+    );
+
+    print $AoA[2][2];
+  bart
+

你å¯èƒ½å·²ç»æ³¨æ„到,外é¢çš„括å·æ˜¯åœ†æ‹¬å·ï¼Œè¿™æ˜¯å› ä¸ºæˆ‘们想è¦ç»™æ•°ç»„赋值,所以 需è¦åœ†æ‹¬å·ã€‚如果你希望这里是 @AoA,而是一个指å‘它的引用,那么就得 这样:

+
    # 一个指å‘“包å«æœ‰æ•°ç»„引用的数组â€çš„引用
+    $ref_to_AoA = [
+        [ "fred", "barney", "pebbles", "bambam", "dino", ],
+        [ "homer", "bart", "marge", "maggie", ],
+        [ "george", "jane", "elroy", "judy", ],
+    ];
+
+    print $ref_to_AoA->[2][2];
+

注æ„外é¢çš„括å·çŽ°åœ¨å˜æˆäº†æ–¹æ‹¬å·ï¼Œå¹¶ä¸”我们的访问语法也有所改å˜ã€‚这时因为 å’Œ C ä¸åŒï¼Œåœ¨ Perl 中你ä¸èƒ½è‡ªç”±åœ°äº¤æ¢æ•°ç»„和引用(在 C 中,数组和指针在 很多地方å¯ä»¥äº’相代替使用)。$ref_to_AoA 是一个数组引用,而 @AoA 是一个 数组。åŒæ ·åœ°ï¼Œ$AoA[2] 也ä¸æ˜¯ä¸€ä¸ªæ•°ç»„,而是一个数组引用。所以下é¢è¿™ 两行:

+
    $AoA[2][2]
+    $ref_to_AoA->[2][2]
+

也å¯ä»¥ç”¨è¿™ä¸¤è¡Œæ¥ä»£æ›¿ï¼š

+
    $AoA[2]->[2]
+    $ref_to_AoA->[2]->[2]
+

这是因为这里有两个相邻的括å·ï¼ˆä¸ç®¡æ˜¯æ–¹æ‹¬å·è¿˜æ˜¯èŠ±æ‹¬å·ï¼‰ï¼Œæ‰€ä»¥ä½ å¯ä»¥éšæ„ 地çœç•¥ç®­å¤´ç¬¦å·ã€‚但是如果 $ref_to_AoA åŽé¢çš„那个箭头ä¸èƒ½çœç•¥ï¼Œå› ä¸ºçœç•¥ äº†å°±æ²¡æ³•çŸ¥é“ $ref_to_AoA 到底是引用还是数组了 ^_^。

+

修改二维数组

+

前é¢çš„例å­é‡Œæˆ‘们创建了包å«æœ‰å›ºå®šæ•°æ®çš„二维数组,但是如何往其中添加新元 素呢?å†æˆ–者如何从零开始创建一个二维数组呢?

+

首先,让我们试ç€ä»Žä¸€ä¸ªæ–‡ä»¶ä¸­è¯»å–二维数组。首先我们演示如何一次性添加一 行。首先我们å‡è®¾æœ‰è¿™æ ·ä¸€ä¸ªæ–‡æœ¬æ–‡ä»¶ï¼šæ¯ä¸€è¡Œä»£è¡¨äº†äºŒç»´æ•°ç»„的行,而æ¯ä¸€ä¸ª å•è¯ä»£è¡¨äº†äºŒç»´æ•°ç»„的一个元素。下é¢çš„代ç å¯ä»¥æŠŠå®ƒä»¬å‚¨å­˜åˆ° @AoA:

+
    while (<>) {
+        @tmp = split;
+        push @AoA, [ @tmp ];
+    }
+

你也å¯ä»¥ç”¨ä¸€ä¸ªå‡½æ•°æ¥ä¸€æ¬¡è¯»å–一行:

+
    for $i ( 1 .. 10 ) {
+        $AoA[$i] = [ somefunc($i) ];
+    }
+

或者也å¯ä»¥ç”¨ä¸€ä¸ªä¸´æ—¶å˜é‡æ¥ä¸­è½¬ä¸€ä¸‹ï¼Œè¿™æ ·çœ‹èµ·æ¥æ›´æ¸…楚些:

+
    for $i ( 1 .. 10 ) {
+        @tmp = somefunc($i);
+        $AoA[$i] = [ @tmp ];
+    }
+

注æ„æ–¹æ‹¬å· [] 在这里éžå¸¸é‡è¦ã€‚方括å·å®žé™…ä¸Šæ˜¯æ•°ç»„å¼•ç”¨çš„æž„é€ å™¨ã€‚å¦‚æžœä¸ ç”¨æ–¹æ‹¬å·è€Œç›´æŽ¥å†™ï¼Œé‚£å°±çŠ¯äº†å¾ˆä¸¥é‡çš„错误:

+
    $AoA[$i] = @tmp;
+

你看,把一个数组赋值给了一个标é‡ï¼Œé‚£ä¹ˆå…¶ç»“æžœåªæ˜¯è®¡ç®—了 @tmp 数组的元素个 数,我想这肯定ä¸æ˜¯ä½ å¸Œæœ›çš„。

+

如果你打开了 use strict,那么你就得先定义一些å˜é‡ç„¶åŽæ‰èƒ½é¿å…警告:

+
    use strict;
+    my(@AoA, @tmp);
+    while (<>) {
+        @tmp = split;
+        push @AoA, [ @tmp ];
+    }
+

当然,你也å¯ä»¥ä¸è¦ä¸´æ—¶å˜é‡ï¼š

+
    while (<>) {
+        push @AoA, [ split ];
+    }
+

如果你知é“想è¦æ”¾åœ¨ä»€ä¹ˆåœ°æ–¹çš„è¯ï¼Œä½ ä¹Ÿå¯ä»¥ä¸è¦ push(),而是直接进行赋值:

+
    my (@AoA, $i, $line);
+    for $i ( 0 .. 10 ) {
+        $line = <>;
+        $AoA[$i] = [ split ' ', $line ];
+    }
+

甚至是这样:

+
    my (@AoA, $i);
+    for $i ( 0 .. 10 ) {
+        $AoA[$i] = [ split ' ', <> ];
+    }
+

你å¯èƒ½ç”Ÿæ€• <> 在列表上下文会出差错,所以想è¦æ˜Žç¡®åœ°å£°æ˜Žè¦åœ¨æ ‡é‡ä¸Šä¸‹æ–‡ä¸­ 对 <> 求值,这样å¯è¯»æ€§ä¼šæ›´å¥½ä¸€äº›ï¼š (译者注:列表上下文中,<> 返回所有的行,标é‡ä¸Šä¸‹æ–‡ä¸­ <> åªè¿”回一行。)

+
    my (@AoA, $i);
+    for $i ( 0 .. 10 ) {
+        $AoA[$i] = [ split ' ', scalar(<>) ];
+    }
+

如果你想用 $ref_to_AoA 这样的一个引用æ¥ä»£æ›¿æ•°ç»„,那你就得这么写:

+
    while (<>) {
+        push @$ref_to_AoA, [ split ];
+    }
+

现在你已ç»çŸ¥é“如何添加新行了。那么如何添加新列呢?如果你正在åšæ•°å­¦ä¸­çš„ 矩阵è¿ç®—,那么è¦å®Œæˆç±»ä¼¼çš„任务:

+
    for $x (1 .. 10) {
+        for $y (1 .. 10) {
+            $AoA[$x][$y] = func($x, $y);
+        }
+    }
+
+    for $x ( 3, 7, 9 ) {
+        $AoA[$x][20] += func2($x);
+    }
+

想è¦è®¿é—®çš„æŸä¸ªå…ƒç´ æ˜¯ä¸æ˜¯å­˜åœ¨æ˜¯æ— å…³ç´§è¦çš„:因为如果ä¸å­˜åœ¨é‚£ä¹ˆ Perl 会给 你自动创建ï¼æ–°åˆ›å»ºçš„元素的值是 undef

+

如果你想添加到一行的末尾,你å¯ä»¥è¿™ä¹ˆåšï¼š

+
    # 添加新列到已存在的行
+    push @{ $AoA[0] }, "wilma", "betty";
+

注æ„我没有这么写:

+
    push $AoA[0], "wilma", "betty";  # 错误ï¼
+

事实上,上é¢è¿™å¥æ ¹æœ¬å°±æ²¡æ³•é€šè¿‡ç¼–译ï¼ä¸ºä»€ä¹ˆï¼Ÿå› ä¸º push() 的第一个å‚æ•°å¿… 须是一个真实的数组,ä¸èƒ½æ˜¯å¼•ç”¨ã€‚

+

访问和打å°

+

现在是打å°äºŒç»´æ•°ç»„的时候了。那么怎么打å°ï¼Ÿå¾ˆç®€å•ï¼Œå¦‚果你åªæƒ³æ‰“å°ä¸€ä¸ªå…ƒ 素,那么就这么æ¥ä¸€ä¸‹ï¼š

+
    print $AoA[0][0];
+

如果你想打å°æ•´ä¸ªæ•°ç»„,那你å¯ä¸èƒ½è¿™æ ·ï¼š

+
    print @AoA;         # 错误ï¼
+

因为你这么åšåªèƒ½å¾—到一列引用,Perl 从æ¥éƒ½ä¸ä¼šè‡ªåŠ¨åœ°ä¸ºä½ è§£å¼•ç”¨ã€‚作为替 代,你必须得弄个循环或者是åŒé‡å¾ªçŽ¯ã€‚用 shell 风格的 for() 语å¥å°±å¯ä»¥ 打å°æ•´ä¸ªäºŒç»´æ•°ç»„:

+
    for $aref ( @AoA ) {
+        print "\t [ @$aref ],\n";
+    }
+

如果你è¦ç”¨ä¸‹æ ‡æ¥é历的è¯ï¼Œä½ å¾—这么åšï¼š

+
    for $i ( 0 .. $#AoA ) {
+        print "\t elt $i is [ @{$AoA[$i]} ],\n";
+    }
+

或者这样用åŒé‡å¾ªçŽ¯ï¼ˆæ³¨æ„内循环):

+
    for $i ( 0 .. $#AoA ) {
+        for $j ( 0 .. $#{$AoA[$i]} ) {
+            print "elt $i $j is $AoA[$i][$j]\n";
+        }
+    }
+

如åŒä½ çœ‹åˆ°çš„一样,它有点儿å¤æ‚。这就是为什么有时候用临时å˜é‡èƒ½å¤Ÿçœ‹èµ·æ¥ 更简å•ä¸€äº›çš„原因:

+
    for $i ( 0 .. $#AoA ) {
+        $aref = $AoA[$i];
+        for $j ( 0 .. $#{$aref} ) {
+            print "elt $i $j is $AoA[$i][$j]\n";
+        }
+    }
+

哦,好åƒè¿˜æœ‰ç‚¹å¤æ‚,那么试试这样:

+
    for $i ( 0 .. $#AoA ) {
+        $aref = $AoA[$i];
+        $n = @$aref - 1;
+        for $j ( 0 .. $n ) {
+            print "elt $i $j is $AoA[$i][$j]\n";
+        }
+    }
+

切片

+

切片是指数组的一部分。如果你想è¦å¾—到多维数组的一个切片,那你得进行一些 下标è¿ç®—。通过箭头å¯ä»¥æ–¹ä¾¿åœ°ä¸ºå•ä¸ªå…ƒç´ è§£å¼•ç”¨ï¼Œä½†æ˜¯è®¿é—®åˆ‡ç‰‡å°±æ²¡æœ‰è¿™ä¹ˆå¥½ 的事了。当然,我们å¯ä»¥é€šè¿‡å¾ªçŽ¯æ¥å–切片。

+

我们先演示如何用循环æ¥èŽ·å–切片。我们å‡è®¾ @AoA å˜é‡çš„值和å‰é¢ä¸€æ ·ã€‚

+
    @part = ();
+    $x = 4;
+    for ($y = 7; $y < 13; $y++) {
+        push @part, $AoA[$x][$y];
+    }
+

这个循环其实å¯ä»¥ç”¨ä¸€ä¸ªåˆ‡ç‰‡æ“作æ¥ä»£æ›¿ï¼š

+
    @part = @{ $AoA[4] } [ 7..12 ];
+

不过这个看上去似乎略微有些å¤æ‚。

+

下é¢å†æ•™ä½ å¦‚何æ‰èƒ½å¾—到一个 二维切片, 比如 $x 从 4 到 8,$y 从 7 到 12,应该怎么写?

+
    @newAoA = ();
+    for ($startx = $x = 4; $x <= 8; $x++) {
+        for ($starty = $y = 7; $y <= 12; $y++) {
+            $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y];
+        }
+    }
+

也å¯ä»¥çœç•¥æŽ‰ä¸­é—´çš„那层循环:

+
    for ($x = 4; $x <= 8; $x++) {
+        push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ];
+    }
+

其实用 map 函数å¯ä»¥æ›´åŠ ç®€ç»ƒï¼š

+
    @newAoA = map { [ @{ $AoA[$_] } [ 7..12 ] ] } 4 .. 8;
+

虽然你的ç»ç†ä¹Ÿè®¸ä¼šæŠ±æ€¨è¿™ç§éš¾ä»¥ç†è§£çš„代ç å¯èƒ½ä¼šå¸¦æ¥å®‰å…¨éšæ‚£ï¼Œ 然而这ç§è§‚点还是颇有争议的(兴许还å¯ä»¥æ›´åŠ å®‰å…¨ä¹Ÿè¯´ä¸å®š ^_^)。 æ¢äº†æ˜¯æˆ‘,我会把它们放进一个函数中实现:

+
    @newAoA = splice_2D( \@AoA, 4 => 8, 7 => 12 );
+    sub splice_2D {
+        my $lrr = shift;        # 指å‘二维数组的引用
+        my ($x_lo, $x_hi,
+            $y_lo, $y_hi) = @_;
+
+        return map {
+            [ @{ $lrr->[$_] } [ $y_lo .. $y_hi ] ]
+        } $x_lo .. $x_hi;
+    }
+

参è§

+

perldata(1), perlref(1), perldsc(1)

+

作者

+

Tom Christiansen <tchrist@perl.com>

+

Last update: Thu Jun 4 16:16:23 MDT 1998

+

翻译者åŠç¿»è¯‘声明

+

本文由 flw ("flw@cpan.org") 翻译,翻译æˆæžœé¦–次出现在 *中国 Perl å会* http://www.perlchina.org) çš„å作开å‘å¹³å°ä¸Šã€‚

+

PerlChina.org 本ç€â€œåœ¨å›½å†…推广 Perlâ€ çš„ç›®çš„ï¼Œç»„ç»‡äººå‘˜ç¿»è¯‘æœ¬æ–‡ã€‚è¯»è€…å¯ ä»¥åœ¨éµå®ˆåŽŸä½œè€…许å¯åè®®ã€å°Šé‡åŽŸä½œè€…åŠè¯‘作者劳动æˆæžœçš„å‰æ下,任æ„å‘布或 修改本文。

+

本文作者用一ç§è½»æ¾åœ°å£å»ç®€è¦ä»‹ç»äº†ä¸€ä¸‹äºŒç»´æ•°ç»„的用法,但是正因如此,文 中有些内容直译过æ¥å而很拗å£ã€å¾ˆéš¾æ‡‚(毕竟中西方文化ä¸åŒå˜›ï¼‰ï¼Œå› æ­¤è¯‘者 在翻译时,对原文有较多的修改。喜欢阅读英文原版胜过喜欢翻译版的朋å‹ä»¬ï¼Œ å¯ä»¥ç›´æŽ¥çœ‹åŽŸç‰ˆ ^_^,åŒæ—¶ä¹Ÿå¸Œæœ›èƒ½å¤Ÿç†è§£è¯‘者的一篇苦心,而ä¸è¦åœ¨èƒŒåŽéª‚我 翻译得ä¸å¯¹å°±æ˜¯äº†ã€‚

+

希望本文能对英文ä¸å¥½çš„朋å‹ä»¬æœ‰æ‰€å¸®åŠ©ã€‚

+

如果你对本文有任何æ„è§ï¼Œæ¬¢è¿Žæ¥ä¿¡æŒ‡æ•™ã€‚本人éžå¸¸æ¬¢è¿Žä¸Žå„ä½äº¤æµã€‚

+ + diff --git a/POD/CN_html/perlobj.html b/POD/CN_html/perlobj.html new file mode 100644 index 0000000..f4a5790 --- /dev/null +++ b/POD/CN_html/perlobj.html @@ -0,0 +1,261 @@ + + + + perlobj + + + + +

NAME

+

perlobj - Perl 对象

+

说明

+

首先你必须懂得在 Perl 中,什么å«åšâ€œå¼•ç”¨â€ï¼Œå¦‚果你还ä¸æ‡‚,那么请å‚考 perlref。 其次,如果你ä»ç„¶æ„Ÿåˆ°ä¸‹æ–‡å‡ºçŽ°çš„引用过于å¤æ‚çš„è¯ï¼Œé‚£ä¹ˆè¯·å…ˆé˜…读 perltoot å’Œ perltooc 这两个 Perl çš„é¢å‘对象编程åˆçº§æ•™ç¨‹ã€‚

+

首先让我们æ¥çœ‹çœ‹æœ‰å…³ Perl é¢å‘对象编程的三个基本定义:

+
    +
  1. 一个“对象â€æ˜¯æŒ‡ä¸€ä¸ªâ€œæœ‰åŠžæ³•çŸ¥é“它是属于哪个类â€çš„简å•å¼•ç”¨ã€‚
  2. +
  3. 一个“类â€æ˜¯æŒ‡ä¸€ä¸ªâ€œæœ‰åŠžæ³•ç»™å±žäºŽå®ƒçš„对象æ供一些方法â€çš„简å•çš„包。
  4. +
  5. 一个“方法â€æ˜¯æŒ‡ä¸€ä¸ªâ€œæŽ¥å—一个对象或者类å称作为第一个å‚æ•°â€çš„简å•çš„å­ç¨‹åºã€‚
  6. +
+

我们暂时ä¸è€ƒè™‘从更深一层的角度æ¥è®²ï¼Œä»¥ä¸Šè¯´æ³•æ˜¯å¦æ­£ç¡®ã€‚

+

对象仅仅åªæ˜¯å¼•ç”¨

+

和 C++ ä¸åŒï¼ŒPerl 没有为“构造函数â€æ供任何特殊的语法(译者注:在 C++ 中,和类å称相åŒçš„类方法被称为“构造函数â€ï¼Œåˆ›å»ºå¯¹è±¡æ—¶è¢«è‡ªåŠ¨è°ƒç”¨ï¼‰ã€‚Perl 中,构造器(译者注:因为 Perl ä¸å¼ºè°ƒâ€œå‡½æ•°â€è¿™ä¸ªæ¦‚念,因此在下文中一律译 为“构造器â€ï¼‰åªæ˜¯ä¸€ä¸ªä¼šè¿”回一个“ç»è¿‡ bless 处ç†â€çš„引用的å­ç¨‹åºï¼Œè¿™ä¸ª ç»è¿‡ bless 处ç†çš„引用就是人们所说的“对象â€ï¼Œè€Œ bless 的作用就是用æ¥è¯´æ˜Ž 这个对象是隶属于哪个“类â€ã€‚

+

下é¢å°±æ˜¯ä¸€ä¸ªå…¸åž‹çš„构造器的例å­ï¼š

+
    package Critter;
+    sub new { bless {} }
+

new 这个è¯å¹¶æ²¡æœ‰ä»»ä½•ç‰¹æ®Šçš„å«ä¹‰ï¼Œå¦‚果你喜欢,你也å¯ä»¥å†™æˆè¿™æ ·ï¼š

+
    package Critter;
+    sub spawn { bless {} }
+

这æ ·åšä¸ä¼šä½¿ C++ 程åºå‘˜è¯¯ä»¥ä¸º new 有什么特殊的å«ä¹‰ï¼Œå› æ­¤æˆ–许更加åˆç†ä¸€ 些。我们建议你给你的构造器起å时尽é‡é€‰æ‹©èƒ½å¤Ÿå‡†ç¡®å映它在你的解决方案中的 æ„义的å字。而ä¸è¦æ‹˜æ³¥äºŽ new 或者其它那些åƒç¯‡ä¸€å¾‹çš„å字。例如在 Perl/Tk 中,组件的构造器就å«åšâ€œcreateâ€ã€‚

+

和 C++ 相比,Perl 的构造器有一点ä¸åŒï¼Œé‚£å°±æ˜¯å®ƒä¸ä¼šè‡ªåŠ¨è°ƒç”¨åŸºç±»çš„构造器。 因为 hash å¯ä»¥è½»æ˜“地表示“åå­—=>值â€è¿™æ ·çš„属性对,因此通常我们用一个匿å hash 引用æ¥å‚¨å­˜å¯¹è±¡çš„å„ä¸ªå±žæ€§ã€‚åœ¨ä¸Šä¾‹ä¸­ï¼Œç”¨ä¸€å¯¹å¤§æ‹¬å· {} å¯ä»¥ç”Ÿæˆä¸€ä¸ª 空的匿å hash å¼•ç”¨ï¼Œç„¶åŽ bless() 函数给它打上一个å°è®°ï¼Œè®©å®ƒå˜æˆä¸€ä¸ª Critter 类的对象,最åŽè¿”回这个对象。这åªæ˜¯ä¸€ä¸ªç®€ä¾¿å†™æ³•ï¼šå› ä¸ºå¯¹è±¡è‡ªèº«çŸ¥é“ 它是被 bless 过的,并且 bless {} 正好是 sub new 的最åŽä¸€ä¸ªè¯­å¥(也是唯一 的语å¥),所以å¯ä»¥ç›´æŽ¥åšä¸ºè¿”回值,ä¸éœ€è¦æ˜¾å¼åœ° return。

+

实际上,sub new { bless {} } 写全了相当于下é¢çš„代ç æ®µï¼š

+
    sub new {
+            my $self = {};
+            bless $self;
+            return $self;
+    }
+

有时候你ç»å¸¸ä¼šè§åˆ°æ›´å¤æ‚一些的构造器,比如它å¯èƒ½ä¼šè°ƒç”¨å¦å¤–一个方法去åšä¸€ 些构造工作:

+
    sub new {
+            my $self = {};
+            bless $self;
+            $self->initialize();    # 注æ„这里
+            return $self;
+    }
+

如果你å°å¿ƒåœ°å¤„ç†ç»§æ‰¿çš„è¯ï¼ˆè¿™ç§æƒ…况ç»å¸¸ç¢°åˆ°ï¼Œå‚è§ ""模å—的创建ã€ä½¿ç”¨å’Œé‡ç”¨" in perlmodlib),那么你å¯ä»¥ç”¨ä¸¤ä¸ªå‚æ•°æ¥è°ƒç”¨ bless,因此你的构造器就å¯ä»¥å®žçŽ°ç»§æ‰¿ï¼š

+
    sub new {
+        my $class = shift;
+        my $self = {};
+        bless $self, $class;
+        $self->initialize();
+        return $self;
+    }
+

如果你希望用户ä¸ä»…能够用 CLASS->new() è¿™ç§å½¢å¼æ¥è°ƒç”¨ä½ çš„构造函 数,还能够以 $obj->new() 这样的形å¼æ¥è°ƒç”¨çš„è¯ï¼Œé‚£ä¹ˆå°±è¿™ä¹ˆåšï¼š

+
    sub new {
+        my $this = shift;
+        my $class = ref($this) || $this;
+        my $self = {};
+        bless $self, $class;
+        $self->initialize();
+        return $self;
+    }
+

需è¦æ³¨æ„的是,这样作并ä¸ä¼šå‘生任何拷è´åŠ¨ä½œã€‚如果你希望拷è´ä¸€ä¸ªå¯¹è±¡ï¼Œé‚£ 么你需è¦è‡ªå·±å†™ä»£ç å¤„ç†ã€‚æŽ¥ä¸‹æ¥ bless 的第二个å‚æ•° $class 所属的 initialize() 方法将被调用。

+

在类的内部,所有的方法都把对象当作一个普通的引用æ¥ä½¿ç”¨ã€‚而在类的外部,用 户åªèƒ½çœ‹åˆ°ä¸€ä¸ªç»è¿‡å°è£…的对象,所有的值都是ä¸é€æ˜Žçš„,åªèƒ½é€šè¿‡ç±»çš„方法æ¥è®¿ 问。

+

虽然ç†è®ºä¸Šæˆ‘们å¯ä»¥åœ¨æž„造器中é‡æ–° bless 一个对象到别的类。对一个对象å†æ¬¡ 进行 bless,将导致这个对象术语新类,而忘记原先的è€ç±»ã€‚我们应该ä¿æŒä¸€ä¸ªå¯¹ 象始终åªå±žäºŽä¸€ä¸ªï¼Œæ‰€ä»¥æˆ‘们ä¸å»ºè®®è¿™ä¹ˆåšã€‚但是如果有è°çœŸçš„这么åšï¼Œé‚£çº¯ç²¹æ˜¯ 自找麻烦。

+

澄清一下:对象是ç»è¿‡ bless 的,引用å˜é‡åˆ™æ²¡æœ‰ã€‚对象知é“它被 bless 到了哪 个类,而引用å˜é‡ä¸çŸ¥é“。bless 处ç†çš„实际上是引用指å‘的对象,而ä¸æ˜¯å¼•ç”¨å˜ é‡è‡ªèº«ã€‚考虑下é¢çš„例å­ï¼š

+
    $a = {};
+    $b = $a;
+    bless $a, BLAH;
+    print "\$b is a ", ref($b), "\n";
+

结果显示 $b 也被 bless 到 BLAH 类了,由此å¯è§ï¼Œbless() æ“ä½œçš„æ˜¯å¯¹è±¡è€Œä¸ æ˜¯å¼•ç”¨å˜é‡ã€‚

+

一个类åªæ˜¯ä¸€ä¸ªç®€å•çš„包

+

和 C++ ä¸åŒï¼ŒPerl 并ä¸ä¸ºç±»å®šä¹‰æ供任何特殊语法。实际上类åªæ˜¯ä¸€ä¸ªåŒ…而已。 ä½ å¯ä»¥æŠŠä¸€ä¸ªåŒ…当作一个类用,并且把包里的函数当作类的方法æ¥ç”¨ã€‚

+

不过,有一个特殊的数组,å«åš @ISA,它说明了“当 Perl 在当å‰åŒ…中找ä¸åˆ°æƒ³ è¦çš„方法时,应当继续从哪儿去找â€ã€‚这就是 Perl 实现“继承â€çš„关键。@ISA 中的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ªåˆ«çš„包的å字。当类找ä¸åˆ°æ–¹æ³•æ—¶ï¼Œå®ƒä¼šä»Ž @ISA 数组中 ä¾æ¬¡å¯»æ‰¾ï¼ˆæ·±åº¦ä¼˜å…ˆï¼‰ã€‚类通过访问 @ISA æ¥çŸ¥é“哪些类是它的基类。

+

所有的类都有一个éšå«çš„基类(祖先类):UNIVERSALUNIVERSAL 类为它 çš„å­ç±»æ供几个通用的类方法。å‚è§ "默认的 UNIVERSAL 方法" 得到更多说明。

+

如果在基类中找到了缺失的方法,那么为了æ高效率,它会被缓存到当å‰ç±»ã€‚æ¯ å½“ä¿®æ”¹äº† @ISA 或者定义了新的å­ç¨‹åºæ—¶ï¼Œç¼“存会失效,这将导致 Perl é‡æ–°åš 一次查找。

+

如果在当å‰ç±»ã€å½“å‰ç±»æ‰€æœ‰çš„基类ã€è¿˜æœ‰ UNIVERSAL 类中都找ä¸åˆ°è¯·æ±‚的方法, 这时会å†æ¬¡æŸ¥æ‰¾å为 AUTOLOAD() 的一个方法。如果找到了 AUTOLOAD,那么就会 调用,åŒæ—¶è®¾å®šå…¨å±€å˜é‡ $AUTOLOAD 的值为缺失的方法的全é™å®šå称。

+

如果还ä¸è¡Œï¼Œé‚£ä¹ˆ Perl 就宣告失败并出错。

+

如果你ä¸æƒ³ç»§æ‰¿åŸºç±»çš„ AUTOLOAD,很简å•ï¼Œåªéœ€è¦ä¸€å¥

+
        sub AUTOLOAD;
+

就行了。然åŽè°ƒç”¨ AUTOLOAD 时就会失败。

+

Perl ç±»åªæœ‰æ–¹æ³•ç»§æ‰¿ã€‚æ•°æ®ç»§æ‰¿ç”±ç¨‹åºå‘˜è‡ªå·±å®žçŽ°ã€‚基本上,对 Perl æ¥è®²è¿™ä¸ 是一个什么大问题:因为我们大多数时候都用匿å hash æ¥å‚¨å­˜å¯¹è±¡æ•°æ®ï¼Œè€Œæ¯ 一层的基类都å¯ä»¥å¾€ hash 表中加入自己的属性,因此å­ç±»è‡ªç„¶å°±å¯ä»¥ç»§æ‰¿åŸºç±» 的属性。唯一的问题å‘生在基类和å­ç±»ä½¿ç”¨äº†åŒä¸€ä¸ªå字作为 hash é”®å€¼æ—¶ã€‚ä¸ é˜²å‡è®¾åŸºç±»å·²ç»ä½¿ç”¨äº† 'city' 这个键å,这时å­ç±»ä¸­ä¹Ÿæƒ³ç”¨ 'city' 这个键, 那么很明显将会覆盖,由于å­ç±»åœ¨è®¾è®¡æ—¶æ— æ³•çŸ¥é“父类中是å¦å·²ç»ä½¿ç”¨äº† 'city' 所以似乎这的确是一个问题。有一个å˜é€šæ–¹æ³•å°±æ˜¯ï¼Œæ¯ä¸€å±‚类都优先考虑使用自 己的包å称作为 hash 键的å‰ç¼€ï¼š

+
    sub bump {
+        my $self = shift;
+        $self->{ __PACKAGE__ . ".count"}++;
+    } 
+

这æ ·ä½ å°±å¯ä»¥åœ¨çˆ¶ç±»å’Œå­ç±»ä¸­è®¿é—®åŒä¸€ä¸ªå±žæ€§çš„ä¸åŒç‰ˆæœ¬ã€‚

+

一个方法就是一个简å•çš„å­ç¨‹åº

+

和 C++ ä¸åŒï¼ŒPerl ä¸æ供任何特殊的语法æ¥å®šä¹‰æ–¹æ³•ã€‚(ä¸è¿‡ Perl æ供了一 个特殊的语法用æ¥è°ƒç”¨æ–¹æ³•ï¼Œç¨åŽå†è®²ï¼‰ã€‚方法把它被调用时的对象或者类å称 当作它的第一个å‚数。有两ç§ä¸åŒçš„调用方法的途径,分别æˆä¸ºâ€œè°ƒç”¨ç±»æ–¹æ³•â€ 和“调用实例方法â€ã€‚

+

类方法把类å当作第一个å‚数。它æ供针对类的功能,而ä¸æ˜¯é’ˆå¯¹æŸä¸ªå…·ä½“的对 象的功能。构造器通常是一个类方法,å‚è§ perltoot 或者 perltooc。 大多数类方法简å•åœ°å¿½ç•¥ç¬¬ä¸€ä¸ªå‚数,因为方法知é“自己处在什么类里é¢ï¼Œä¹Ÿä¸ 关心它是通过什么类æ¥è°ƒç”¨çš„。(调用类和所处类ä¸ä¸€å®šç›¸åŒï¼Œä¾‹å¦‚基类的方法 被å­ç±»è°ƒç”¨æ—¶ï¼Œæ–¹æ³•çš„所处类是基类,而调用类是å­ç±»ï¼Œç±»æ–¹æ³•å’Œå¯¹è±¡æ–¹æ³•éƒ½æ˜¯ 如此。) 举个常è§çš„例å­ï¼Œä¸‹é¢çš„类方法å¯ä»¥é€šè¿‡åå­—æ¥æŸ¥è¯¢å¯¹è±¡ï¼š

+
    sub find {
+        my ($class, $name) = @_;
+        $objtable{$name};
+    }
+

实例方法把对象作为它的第一个å‚数。因此典型的åšæ³•æ˜¯æŠŠç¬¬ä¸€ä¸ªå‚æ•° shift 到一个å为“selfâ€æˆ–者“thisâ€çš„å˜é‡ä¸­ã€‚然åŽå†æŠŠå®ƒå½“作一个引用æ¥ç”¨ï¼š

+
    sub display {
+        my $self = shift;
+        my @keys = @_ ? @_ : sort keys %$self;
+        foreach $key (@keys) {
+            print "\t$key => $self->{$key}\n";
+        }
+    }
+

调用方法

+

出于历å²é—留的原因,Perl æ供了两ç§ä¸åŒçš„å½¢å¼åŽ»è°ƒç”¨ä¸€ä¸ªæ–¹æ³•ã€‚最简å•çš„ å½¢å¼æ˜¯é‡‡ç”¨ç®­å¤´ç¬¦å·ï¼š

+
    my $fred = Critter->find("Fred");
+    $fred->display("Height", "Weight");
+

你å¯ä»¥æ—©å°±ç†Ÿæ‚‰äº†å¼•ç”¨çš„ -> æ“作符。事实上,因为上é¢çš„ $fred 是一个指å‘了对象的引用,因此你也å¯ä»¥æŠŠç®­å¤´æ“作符ç†è§£ä¸ºå¦å¤–一ç§å½¢å¼çš„ 解引用。

+

出现在箭头左边的引用或者类å,将作为第一个å‚数传递给箭头å³è¾¹çš„方法。 所以上é¢çš„代ç å°±åˆ†åˆ«ç›¸å½“于这样:

+
    my $fred = Critter::find("Critter", "Fred");
+    Critter::display($fred, "Height", "Weight");
+

Perl 怎么知é“箭头å³è¾¹çš„å­ç¨‹åºæ˜¯å“ªä¸ªåŒ…里的呢?答案是通过查看箭头左边的 内容。箭头左边必须是一个对象,或者是一个标识类å的字符串。这两ç§æƒ…况 都行。如果类里没有这个方法,那么 Perl 就从基类中进行检索。

+

如果必è¦ï¼Œä½ è¿˜可以强制 Perl 检索其它类:

+
    my $barney = MyCritter->Critter::find("Barney");
+    $barney->Critter::display("Height", "Weight");
+

这个例å­ä¸­ï¼ŒMyCritter 类是 Critter 类的å­ç±»ï¼Œå¹¶ä¸”定义了自己的 find() å’Œ display() 方法。通过加å‰ç¼€ Critter:: å¯ä»¥å¼ºåˆ¶ Perl 执行 Critter 的方法而ä¸æ˜¯ MyCritter 自己的方法。

+

上é¢çš„例å­è¿˜æœ‰ä¸€ç§ç‰¹æ®Šæƒ…形,那就是你å¯ä»¥ç”¨ SUPER 伪类æ¥å‘Šè¯‰ Perl 通过当å‰åŒ…çš„ @ISA 数组æ¥æ£€ç´¢ç©¶ç«Ÿåº”该使用哪个类。

+
    package MyCritter;
+    use base 'Critter';    # sets @MyCritter::ISA = ('Critter');
+
+    sub display { 
+        my ($self, @args) = @_;
+        $self->SUPER::display("Name", @args);
+    }
+

注æ„:SUPER 表示 当å‰åŒ… çš„ 超ç±» 而ä¸æ˜¯ 对象 çš„ 超ç±»。 而且,SUPER 符å·ä»…ä»…åªæ˜¯ä¸€ä¸ªæ–¹æ³•å称的 修饰符,å› æ­¤ä¸èƒ½æŠŠå®ƒå½“作 ç±»å称使用在其它地方。记ä½ï¼šSUPER ä¸æ˜¯ç±»å称,åªæ˜¯ä¿®é¥°ç¬¦ã€‚例如:

+
    something->SUPER::method(...);      # OK
+    SUPER::method(...);                 # WRONG
+    SUPER->method(...);                 # WRONG
+

最åŽä¸€ç‚¹ï¼Œç®­å¤´å·¦è¾¹çš„ç±»å或者对象,也å¯ä»¥ç”¨è¿”回类å或者对象的表达å¼æ¥ä»£ 替。所以下é¢è¿™å¥æ˜¯åˆæ³•çš„:

+
    Critter->find("Fred")->display("Height", "Weight");
+

这å¥ä¹Ÿæ˜¯åˆæ³•çš„:

+
    my $fred = (reverse "rettirC")->find("Fred");
+

间接对象语法

+

另外一ç§è°ƒç”¨æ–¹æ³•çš„æ–¹å¼ç§°ä¸ºâ€œé—´æŽ¥å¯¹è±¡â€è¯­æ³•ã€‚è¿™æ¡è¯­æ³•æ—©åœ¨ Perl4 时代就 å·²ç»å¼•è¿›ï¼Œé‚£æ—¶è¿˜æ²¡æœ‰å¯¹è±¡è¿™ä¸ªæ¦‚念。它也å¯ä»¥ç”¨åœ¨æ–‡ä»¶å¥æŸ„上:

+
   print STDERR "help!!!\n";
+

同样的语法å¯ä»¥è°ƒç”¨å¯¹è±¡æˆ–者类的方法:

+
   my $fred = find Critter "Fred";
+   display $fred "Height", "Weight";
+

注æ„在对象/ç±»å称与å‚数之间ä¸èƒ½æœ‰é€—å·ï¼Œè¿™ç§è¯­æ³•å‘Šè¯‰ Perl 你想è¦è°ƒç”¨ä¸€ 个对象方法而ä¸æ˜¯æ™®é€šçš„å­ç¨‹åºã€‚

+

但是如果没有å‚数怎么办?(译者注:这时方法åŽé¢åªæœ‰ä¸€ä¸ªå¯¹è±¡/ç±»å称,因 æ­¤ä¸èƒ½ä¸€çœ¼çœ‹å‡ºåˆ°åº•æ˜¯æƒ³è°ƒç”¨ä¸€ä¸ªæ–¹æ³•ï¼Œè¿˜æ˜¯ç”¨å¯¹è±¡/ç±»å称åšå‚数调用一个普 通的å­ç¨‹åºï¼‰ã€‚这时,Perl åªèƒ½çŒœæµ‹ä½ çš„想法,更糟糕的是,Perl 是在“编 译时â€å°±è¿›è¡ŒçŒœæµ‹ï¼é€šå¸¸ Perl å¯ä»¥ä½œå‡ºæ­£ç¡®çš„判断,但是有时 Perl 会把一 个函数调用编译æˆä¸€ä¸ªç±»æ–¹æ³•ï¼Œæˆ–者把一个类方法编译æˆä¸€ä¸ªå‡½æ•°è°ƒç”¨ã€‚è¿™å¯ èƒ½ä¼šå¯¼è‡´å‡ºçŽ°éš¾ä»¥å¯Ÿè§‰çš„é”™è¯¯ã€‚

+

例如,有一个 new 方法的间接调用ï¼ï¼C++ 程åºå‘˜é€šå¸¸å–œæ¬¢è¿™ä¹ˆåšï¼ï¼å¯ 能被编译æˆä¸€ä¸ªå­ç¨‹åºè°ƒç”¨ï¼Œå‰æ是如果碰巧在当å‰ä½œç”¨åŸŸæœ‰ä¸€ä¸ªå­ç¨‹åºä¹Ÿå« new。你的代ç æœ€ç»ˆä¼šè°ƒç”¨å½“å‰åŒ…çš„ new å­ç¨‹åºï¼Œè€Œä¸æ˜¯ä½ æƒ³è¦çš„类方法。

+

TODO The compiler tries to cheat by remembering bareword "require"s, but the grief when it messes up just isn't worth the years of debugging it will take you to track down such subtle bugs.

+

这个语法还有一个问题:间接对象仅é™äºŽä¸€ä¸ªå称ã€æˆ–者一个标é‡ã€æˆ–者一个 ,之所以这么åšæ˜¯å› ä¸ºä¼˜å…ˆçº§çš„问题。如果ä¸åŠ è¿™ä¸ªé™åˆ¶çš„è¯ï¼Œå°†å¯¼è‡´ Perl 在分æžä½ çš„程åºæ—¶éœ€è¦å¤šåšå¾ˆå¤šå‘å‰æ‰«æ工作,比如解引用之类的。 这个诡异的规则åŒæ ·é€‚用于 print å’Œ printf

+

请看下é¢çš„两行

+
    move $obj->{FIELD};                 # 很å¯èƒ½æ˜¯é”™çš„ï¼
+    move $ary[$i];                      # 很å¯èƒ½æ˜¯é”™çš„ï¼
+

上é¢ä¸¤è¡Œä»Ž Perl ç†è§£çš„角度æ¥çœ‹ï¼Œç›¸å½“于:

+
    $obj->move->{FIELD};                # 看这儿ï¼
+    $ary->move([$i]);                   # 你真的想这样å—?
+

而你真正希望的也许是:

+
    $obj->{FIELD}->move();              # 这么åšå¤šå¥½
+    $ary[$i]->move;                     # è¿™å¯èƒ½æ‰æ˜¯ä½ çš„æ„æ€ã€‚
+

要想用间接对象语法正确的表达你的æ„图,你得加上花括å·ï¼š

+
    move {$obj->{FIELD}};
+    move {$ary[$i]};
+

即使是这样,还是会存在éšæ‚£ï¼ˆè€ƒè™‘如果当å‰åŒ…就有一个å为 move 的函 数,那么很显然 Perl 会把它ç†è§£æˆå‡½æ•°è°ƒç”¨è€Œä¸æ˜¯é—´æŽ¥å¯¹è±¡è°ƒç”¨ï¼‰ã€‚因此, 我们大力推èä½ åªä½¿ç”¨ ->。ä¸ç®¡æ€Žæ ·ï¼Œä½ ä»ç„¶ä¼šçœ‹åˆ°å¾ˆå¤šä»¥å‰ é—留下æ¥çš„间接对象语法,因此熟悉它们还是很有必è¦çš„。

+

默认的 UNIVERSAL 方法

+

UNIVERSAL 包为它的å­ç±»æ供如下几个方法:

+
+
isa(CLASS)
+
+

如果调用 isa 的对象是隶属于 CLASS 或者它的å­ç±»ï¼Œ 那么 isa 返回 真值

+

你也å¯ä»¥ç”¨ä¼ é€’两个å‚数的办法直接调用 UNIVERSAL::isa:第一个å‚数是 一个对象(甚至是普通的引用),这个办法å¯ä»¥ç”¨æ¥æ£€æŸ¥ä¸€ä¸ªå¯¹è±¡æ˜¯ä¸æ˜¯å±žäºŽ 指定的类型。例如:

+
    if(UNIVERSAL::isa($ref, 'ARRAY')) {
+        #...
+    }
+

要想确定一个引用是ä¸æ˜¯ä¸€ä¸ª bless 过的对象,你å¯ä»¥è¿™ä¹ˆå†™ï¼š

+
    print "It's an object\n" if UNIVERSAL::isa($val, 'UNIVERSAL');
+
+
can(METHOD)
+
+

can 检查一个对象是ä¸æ˜¯æ‹¥æœ‰ä¸€ä¸ªå«åš METHOD 的方法。如果有,那么 将返回那个方法(实际上就是å­ç¨‹åºï¼‰çš„引用。如果没有,那么返回 undef

+

也å¯ä»¥ç”¨ä¸¤ä¸ªå‚æ•°æ¥ç›´æŽ¥è°ƒç”¨ UNIVERSAL::can。当第一个å‚æ•°ä¸æ˜¯ä¸€ä¸ªå¯¹ 象或者是类å的时候,它返回 undef,所以我们也å¯ä»¥ç”¨è¿™ä¸ªåŠžæ³•çŸ¥é“一个 引用是ä¸æ˜¯ä¸€ä¸ªå¯¹è±¡ã€‚

+
    print "It's still an object\n" if UNIVERSAL::can($val, 'can');
+

你也å¯ä»¥ç”¨ Scalar::Util 模å—çš„ blessed 函数æ¥è¾¾åˆ°åŒæ ·çš„目的:

+
    use Scalar::Util 'blessed';
+
+    my $blessing = blessed $suspected_object;
+

如æžœ $suspected_object 是一个对象,那么 blessed 返回对象所属的类å 称,ä¸ç„¶è¿”回 undef

+
+
VERSION( [NEED] )
+
+

VERSION 返回一个类的版本å·ã€‚如果æ供了 NEED å‚数,那么它还会检查 当å‰ç‰ˆæœ¬å·ï¼ˆå°±æ˜¯ç±»é‡Œé¢çš„那个 $VERSION å˜é‡ï¼‰æ˜¯ä¸æ˜¯å°äºŽ NEEDï¼Œå¦‚æžœå° äºŽï¼Œå®ƒä¼šå¯¼è‡´ Perl ç¨‹åº die。此方法通常作为一个类方法æ¥è°ƒç”¨ã€‚

+

use 语å¥ä¸­ä¼šè‡ªåŠ¨è°ƒç”¨æ­¤æ–¹æ³•ï¼Œè¯·çœ‹ä¸‹é¢ï¼š

+
    use A 1.2 qw(some imported subs);
+

上é¢çš„语å¥ç›¸å½“于éšå«åœ°è°ƒç”¨äº†ï¼š

+
    A->VERSION(1.2);
+
+
+

注æ„: can 直接在 Perl 内部实现,isa 也是,并且还采用了缓冲 技术。因此当你的程åºåŠ¨æ€åœ°ä¿®æ”¹ @ISA 数组时,å¯èƒ½ä¼šå‡ºçŽ°ç¨€å¥‡å¤æ€ªçš„问题。

+

你也å¯ä»¥é€šè¿‡ Perl 程åºæˆ–者 XS 程åºè‡ªå·±ç»™ UNIVERSAL 类添加方法,并且 ä¸éœ€è¦ use UNIVERSAL å°±å¯ä»¥åœ¨ä½ çš„程åºä¸­ä½¿ç”¨æ–°åŠ çš„方法。

+

析构器

+

当对象的最åŽä¸€ä¸ªå¼•ç”¨é‡Šæ”¾æ—¶ï¼Œå¯¹è±¡ä¼šè‡ªåŠ¨æžæž„。(如果你把对象储存在全局 å˜é‡ä¸­ï¼Œé‚£ä¹ˆä¸€ç›´åˆ°ä½ çš„程åºé€€å‡ºæ—¶æ‰ä¼šæžæž„)。如果你想在æžæž„的时候åšäº› 什么,那么你å¯ä»¥åœ¨ç±»ä¸­å®šä¹‰ä¸€ä¸ªå为“DESTROYâ€çš„方法。它将在适åˆçš„时机 自动调用,并且按照你的æ„æ€æ‰§è¡Œé¢å¤–的清ç†åŠ¨ä½œã€‚Perl 会把对象的引用作为 唯一的å‚数传递给 DESTROY。注æ„这个引用是åªè¯»çš„,也就是说你ä¸èƒ½é€šè¿‡è®¿é—® $_[0] æ¥ä¿®æ”¹å®ƒã€‚(译者注:å‚è§ perlsub)但是对象自身(比如 ${$_[0] 或者 @{$_[0]} 还有 %{$_[0]} 等等)还是å¯å†™çš„,

+

如果你在æžæž„器返回之å‰é‡æ–° bless 了对象引用,那么 Perl 会在æžæž„器返回 之åŽæŽ¥ç€è°ƒç”¨ä½ é‡æ–° bless 的那个对象的 DESTROY 方法。这å¯ä»¥è®©ä½ æœ‰æœºä¼š 调用基类或者你指定的其它类的æžæž„器。需è¦è¯´æ˜Žçš„是,DESTROY 也å¯ä»¥æ‰‹å·¥ 调用,但是通常没有必è¦è¿™ä¹ˆåšã€‚

+

在当å‰å¯¹è±¡é‡Šæ”¾åŽï¼ŒåŒ…å«åœ¨å½“å‰å¯¹è±¡ä¸­çš„其它对象会自动释放(å‡å¦‚别的地方没 有什么引用指å‘它们的è¯ï¼‰ã€‚

+

摘è¦

+

以上就是所有的内容了 ^_^。 你现在需è¦åšçš„就是马上出去买本书,关于“é¢å‘对象设计模å¼â€çš„é‚£ç§ï¼ˆç›¸ä¿¡ 很好买到,因为这ç§ä¹¦çŽ°åœ¨æ»¡å¤§è¡—都是)然åŽä¸€å¤´æ‰Žè¿›åŽ»ï¼Œå•ƒä¸Šè‡³å°‘ 6 ä¸ªæœˆå† å‡ºæ¥ ^_^

+

Two-phased 垃圾回收

+

为了更多的目的,Perl 采用了一套快速ã€ç®€ä¾¿ï¼ŒåŸºäºŽå¼•ç”¨è®¡æ•°çš„垃圾回收机制。 è¿™æ„味ç€æœ‰ä¸€äº›é¢å¤–的解引用æ“作å‘生在æŸä¸ªå±‚次,因此如果你ä¸ç”¨ C 编译器 çš„ -O 开关编译你的 Perl çš„è¯ï¼Œæ€§èƒ½ä¼šæœ‰äº›æŸå¤±ï¼Œå¦‚果你的 Perl 已ç» æ˜¯ç”¨ cc -O 编译过的了,那就没什么问题。

+

还有个很严é‡çš„问题:有时候引用计数根本就ä¸å¯èƒ½ä¸º 0,也就是说内存永远 ä¸ä¼šé‡Šæ”¾ã€‚例如下é¢çš„代ç å°±æœ‰è¿™ä¸ªé—®é¢˜ï¼š

+
    {
+        my $a;
+        $a = \$a;
+    }
+

虽然 $a å·²ç»å®Œå…¨è¶…出作用域了,但是它还是ä¸èƒ½é‡Šæ”¾ã€‚当创建递归数æ®ç»“æž„ 时,你必须明确打破这ç§自引用,å¦åˆ™å†…存就会泄æ¼ã€‚例如,下é¢å°±æ˜¯ä¸€ä¸ª 引用了自身的节点(类似的代ç å¯èƒ½ä¼šå‡ºçŽ°åœ¨æ ‘型结构中):

+
    sub new_node {
+        my $class = shift;
+        my $node  = {};
+        $node->{LEFT} = $node->{RIGHT} = $node;
+        $node->{DATA} = [ @_ ];
+        return bless $node => $class;
+    }
+

如果你创建这样的节点,那么内存就会无法自动释放,除éžä½ è‡ªå·±æ‰“断自引用 的结构。æ¢å¥è¯è¯´ï¼Œè¿™ä¸æ˜¯ä¸€ä¸ªç‰¹æ€§ï¼Œæ‰€ä»¥ä½ åˆ«æŒ‡æœ›å®ƒã€‚

+

差ä¸å¤šå°±è¿™äº›ã€‚

+

当一个解释器线程最åŽå¿«è¦é€€å‡ºçš„时候(通常å‘生在你的程åºç»“æŸæ—¶ï¼‰ï¼Œå°±ä¼š 进行垃圾回收,然åŽæ‰€æœ‰è¿™ä¸ªçº¿ç¨‹æ‹¥æœ‰çš„对象都会释放。这一点对于嵌入å¼çš„ Perl 应用或者多线程程åºéžå¸¸é‡è¦ã€‚下é¢è¿™ä¸ªç¨‹åºæ¼”示了 Perl çš„ two-phased 垃圾回收:

+
    #!/usr/bin/perl
+    package Subtle;
+
+    sub new {
+        my $test;
+        $test = \$test;
+        warn "创建 " . \$test;
+        return bless \$test;
+    }
+
+    sub DESTROY {
+        my $self = shift;
+        warn "é”€æ¯ $self";
+    }
+
+    package main;
+
+    warn "开始è¿è¡Œ";
+    {
+        my $a = Subtle->new;
+        my $b = Subtle->new;
+        $$a = 0;  # break selfref
+        warn "å—结æŸä¹‹å‰";
+    }
+
+    warn "å—结æŸä¹‹åŽ";
+    warn "程åºç»“æŸ...";
+    exit;
+

好比我们把它ä¿å­˜æˆ /foo/test,那么输出结果就应该是下é¢è¿™æ ·çš„:

+
    开始è¿è¡Œ at /foo/test line 18.
+    创建 SCALAR(0x8e5b8) at /foo/test line 7.
+    创建 SCALAR(0x8e57c) at /foo/test line 7.
+    å—结æŸä¹‹å‰ at /foo/test line 23.
+    é”€æ¯ Subtle=SCALAR(0x8e5b8) at /foo/test line 13.
+    å—结æŸä¹‹åŽ at /foo/test line 26.
+    程åºç»“æŸ... at /foo/test line 27.
+    é”€æ¯ Subtle=SCALAR(0x8e57c) during global destruction.
+

注æ„看“global destructionâ€è¿™ä¸ªåœ°æ–¹ï¼è¿™é‡Œå°±æ˜¯çº¿ç¨‹çš„垃圾回收阶段。 甚至å¯ä»¥å›žæ”¶è‡ªå¼•ç”¨çš„æ•°æ®ã€‚

+

对象总是è¦æžæž„,并且是在引用还没有æžæž„的时候就进行æžæž„,这样就å¯ä»¥é˜»æ­¢ 把一个已ç»æžæž„的引用进行对象æžæž„。普通引用仅仅åªæœ‰å½“æžæž„层次大于 0 æ—¶ æ‰å¼€å§‹æžæž„。

+

//TODO: You can test the higher levels of global destruction by setting the PERL_DESTRUCT_LEVEL environment variable, presuming -DDEBUGGING was enabled during perl build time. See "PERL_DESTRUCT_LEVEL" in perlhack for more information.

+

一个更加完整的垃圾回收机制将在ä¸ä¹…çš„å°†æ¥å®Œæˆã€‚

+

在此期间,最好的解决方案就是创建一个éžé€’归结构的包容器类,该包容器类包 å«æœ‰ä¸€ä¸ªæŒ‡é’ˆæŒ‡å‘自引用的数æ®ç»“构。然åŽä¸ºè¯¥è¢«åŒ…容的对象类定义一个 DESTROY 方法,用 DESTROY 手工打破自引用的结构的循环。

+

参è§

+

Perl 有几个入门级的é¢å‘对象编程教程,它们是 perltoot, perlboot å’Œ perltooc。你还å¯ä»¥åœ¨ perlbot 里看到关于对象的技巧ã€é™·é˜±ã€å’Œæ示。 å¦å¤–,perlmodlib 中还有一些制作自己的类和模å—的指å—。

+

翻译者åŠç¿»è¯‘声明

+

本文由 flw (flw@cpan.org) 翻译,翻译æˆæžœé¦–次出现在 中国 Perl å会 http://www.perlchina.org) çš„å作开å‘å¹³å°ä¸Šã€‚

+

PerlChina.org 本ç€â€œåœ¨å›½å†…推广 Perlâ€ çš„ç›®çš„ï¼Œç»„ç»‡äººå‘˜ç¿»è¯‘æœ¬æ–‡ã€‚è¯»è€…å¯ ä»¥åœ¨éµå®ˆåŽŸä½œè€…许å¯åè®®ã€å°Šé‡åŽŸä½œè€…åŠè¯‘作者劳动æˆæžœçš„å‰æ下,任æ„å‘布或 修改本文。

+

如果你对本文有任何æ„è§ï¼Œæ¬¢è¿Žæ¥ä¿¡æŒ‡æ•™ã€‚本人éžå¸¸æ¬¢è¿Žä¸Žå„ä½äº¤æµã€‚

+ + diff --git a/POD/CN_html/perlootut.html b/POD/CN_html/perlootut.html new file mode 100644 index 0000000..6d44624 --- /dev/null +++ b/POD/CN_html/perlootut.html @@ -0,0 +1,276 @@ + + + + 描è¿° + + + + +

NAME

+
 perlootut - perl 教程之é¢å‘对象编程
+

描è¿°

+

此文档æ供了一个使用 perl 进行é¢å‘对象编程的介ç»ã€‚开篇是一个简短的关于é¢å‘ 对象设计概念的概述,之åŽä»‹ç»äº†CPAN上基于 perl çš„ å„ç§ OO 系统。

+

默认情况下,perl 内置的 OO 系统éžå¸¸å°å·§ï¼Œè¿™ä½¿ä½ å¿…须自己åšå¤§éƒ¨åˆ†å·¥ä½œã€‚è¿™ç§ å°å·§åœ¨1994年那个时代是åˆç†çš„,但自 perl 5.0å‘布以æ¥ï¼Œè®¸å¤šé€šç”¨çš„模å¼åœ¨ perl OO 系统里é¢æ˜¾çŽ°ã€‚幸è¿çš„是,perl çš„çµæ´»æ€§å…许 perl OO 的生æ€ç³»ç»Ÿæ¼”化和 ç¹è£ã€‚

+

如æžœä½ æƒ³çŸ¥é“ perl OO 底层是如何工作的,perlobj æ供了详细的信æ¯ã€‚

+

此文档å‡è®¾ä½ å·²ç»æŽŒæ¡äº†åŸºæœ¬çš„ perl 语法,å˜é‡ç±»åž‹ï¼Œæ“作符和函数调用。如果你 还ä¸ç†è§£è¿™äº›æ¦‚念,请先阅读 perlintro。åŒæ—¶ä½ è¿˜åº”该阅读 perlsynperlopperlsub

+

面å‘对象基础

+

大部分é¢å‘对象编程系统都有一些通用的概念。你å¯èƒ½å·²ç»å¬è¯´è¿‡äº†ä¸€äº›åƒâ€œç±»â€ï¼Œâ€œ 对象â€ï¼Œâ€œæ–¹æ³•â€å’Œâ€œå±žæ€§â€çš„术语。ç†è§£è¿™äº›æ¦‚å¿µï¼Œä½¿ä½ èƒ½å¤Ÿæ›´åŠ å®¹æ˜“çš„é˜…è¯»å’Œç¼–å†™é¢ å‘对象代ç ã€‚å³ä½¿ä½ å·²ç»ç†Ÿæ‚‰äº†è¿™äº›ï¼Œä½ ä»ç„¶å¯ä»¥é˜…读一下这一节,因为这里用 perl 的术语解释了这些概念。

+

perl çš„ OO 系统基于类(class-based)。基于类的 OO 是相当通用的,java,C++, C#,Python,Ruby 和很多其他语言都是如此。当然也有其他类型的é¢å‘对象。 Javascript 就是使用å¦ä¸€ç§æ¨¡å¼çš„æµè¡Œè¯­è¨€ï¼Œå…¶ OO 系统是基于原型的 (prototype-based)。

+

对象

+

对象是èšåˆäº†æ•°æ®å’Œæ“作数æ®çš„函数的数æ®ç»“构。对象的数æ®å«åš属性,它的 函数å«åš方法。一个对象å¯ä»¥æƒ³è±¡æˆä¸ºä¸€ä¸ªåè¯ï¼ˆä¸€ä¸ªäººï¼Œä¸€ä¸ªç½‘络æœåŠ¡ï¼Œä¸€å° 计算机)。

+

对象代表了一个å•ä¸€ä½†ä¸è¿žç»­çš„物体。比如,它å¯èƒ½ä»£è¡¨ä¸€ä¸ªæ–‡ä»¶ã€‚文件对象的属性 å¯èƒ½åŒ…括路径,内容,最åŽä¿®æ”¹æ—¶é—´ã€‚如果我们创建一个代表 /etc/hostname æ–‡ 件的对象,这个文件存放在å为“foo.example.comâ€çš„机器上。这个对象的路径就应 该是“/etc/hostnameâ€ï¼Œå†…容是“foo\nâ€ï¼Œæœ€åŽä¿®æ”¹æ—¶é—´æ˜¯è‡ª epoch åŽ1304974868秒 。

+

和文件相关的方法å¯ä»¥æœ‰ rename() å’Œ write()

+

perl 的大部分对象都是哈希,如果你使用我们推èçš„ OO 系统,则你完全ä¸å¿…关心 这一点。实际上,最好将对象看åšä¸€ä¸ªä¸é€æ˜Žçš„内部数æ®ç»“构。

+

+

定义了一个类别的对象的行为。类是一个类别的åå­—(比如 "File"),类还定义 了这个类别中的对象的行为。

+

所有的对象都属于æŸä¸ªç‰¹å®šç±»ã€‚比如,我们的 /etc/hostname 对象属于 File 类。当我们想创建一个特定对象时,我们以它的类开始,创建或者实例化一个 对象。对象ç»å¸¸è¢«ç§°ä¸ºä¸€ä¸ªç±»çš„实例

+

在 perl 中,任何包都å¯ä»¥æ˜¯ä¸€ä¸ªç±»ã€‚一个包是å¦ä¸ºç±»çš„区别在于这个包是如何被使 用的。以下是我们的 File 类的"类定义"。

+
  package File;
+

对于 perl æ¥è¯´ï¼Œæ²¡æœ‰ä¸€ä¸ªç‰¹å®šçš„关键字æ¥åˆ›å»ºå¯¹è±¡ï¼Œä½†å¤§éƒ¨åˆ† CPAN 上的 OO æ¨¡å— éƒ½ä½¿ç”¨ä¸€ä¸ªå为 new() 的方法。

+
  my $hostname = File->new(
+      path          => '/etc/hostname',
+      content       => "foo\n",
+      last_mod_time => 1304974868,
+  );
+

(别担心那个->操作符,接下æ¥ä¼šè§£é‡Š)

+

Blessing

+

如å‰æ‰€è¿°ï¼Œå¤§å¤š perl 的对象都是哈希,但它也å¯ä»¥æ˜¯ä»»æ„ perl æ•°æ®ç±»åž‹(æ ‡é‡ï¼Œ 数组等)。把一个普通的 perl æ•°æ®ç»“构转æ¢æˆå¯¹è±¡çš„æ–¹å¼æ˜¯ä½¿ç”¨ bless 函数对 它进行 Blessing

+

尽管我们强烈建议你ä¸è¦ä»Žæœ€åº•å±‚å¼€å§‹åˆ›å»ºä½ çš„å¯¹è±¡ï¼Œä½†ä½ ä¹Ÿåº”è¯¥çŸ¥é“ bless è¿™ 个术语。一个 blessed çš„æ•°æ®ç»“构是一个对象。我们有时候会说一个对象被“ blessed into a classâ€ã€‚

+

当一个å˜é‡è¢« bless åŽï¼ŒScalar::Util 模å—中的 blessed 函数å¯ä»¥å‘Šè¯‰æˆ‘ 们它的类å。当其å‚数为对象时,这个函数返回对象的类,å¦åˆ™è¿”回false。

+
  use Scalar::Util 'blessed';
+
+  print blessed($hash);      # undef
+  print blessed($hostname);  # File
+

构造器

+

构造器用æ¥åˆ›å»ºæ–°å¯¹è±¡ã€‚ä¸åƒå…¶ä»–语言中æ供了构造器语法一样,在 perl 中, 一个类的构造器åªæ˜¯ä¸€ä¸ªæ™®é€šçš„方法。大部分 perl 的类使用 new 作为构造器的 å字。

+
  my $file = File->new(...);
+

方法

+

你å·²ç»çŸ¥é“了方法就是æ“作对象的å­ç¨‹åºã€‚你也å¯ä»¥å°†æ–¹æ³•çœ‹åšå¯¹è±¡èƒ½åšçš„事 情。如果对象是åè¯ï¼Œé‚£ä¹ˆæ–¹æ³•å°±æ˜¯å®ƒçš„动作(ä¿å­˜ï¼Œæ‰“å°ï¼Œæ‰“å¼€)。

+

在 perl 里é¢ï¼Œæ–¹æ³•æ˜¯å®šä¹‰ç±»çš„包里é¢çš„å­ç¨‹åºã€‚方法的第一个å‚数总是对象。

+
  sub print_info {
+      my $self = shift;
+
+      print "This file is at ", $self->path, "\n";
+  }
+
+  $file->print_info;
+  # The file is at /etc/hostname
+

方法的特殊之处在于它是“怎样被调用的â€ã€‚箭头æ“作符->告诉 perl 我们在 调用一个方法。

+

Invocant 是一个有æ„æ€çš„å字,它代表箭头左边的部分。Invocant å¯ä»¥æ˜¯ç±»å或者 一个对象。我们当然也å¯ä»¥ç»™æ–¹æ³•ä¼ é€’其他å‚数。

+
  sub print_info {
+      my $self   = shift;
+      my $prefix = shift // "This file is at ";
+
+      print $prefix, ", ", $self->path, "\n";
+  }
+
+  $file->print_info("The file is located at ");
+  # The file is located at /etc/hostname
+

属性

+

所有的类都å¯ä»¥å®šä¹‰å®ƒçš„属性。当我们åˆå§‹åŒ–一个对象时,我们å¯ä»¥ç»™å±žæ€§èµ‹ 值。比如,æ¯ä¸ª文件对象有一个路径。属性(attributes)有时也å«åš properties

+

Perl 没有用æ¥å®šä¹‰å±žæ€§çš„语法。在底层,属性就是类所对应哈希的键,ä¸è¿‡ä½ ä¸éœ€ è¦å…³æ³¨è¿™ç‚¹ã€‚

+

我们推èä½ åªé€šè¿‡存å–器来访问属性。存å–器是用æ¥èŽ·å¾—或设置属性的值的方法 。我们在print_info() 里é¢å·²ç»çœ‹åˆ°è¿‡äº†: $self->path

+

你å¯èƒ½ä¹Ÿè§è¿‡ getter å’Œ setter 这样的术语。这是两ç§ä¸åŒçš„å­˜å–器。 Getter 用æ¥èŽ·å¾—属性的值,而 setter 用æ¥è®¾ç½®å€¼ã€‚Setter çš„å¦ä¸€ä¸ªå«æ³•æ˜¯ mutator

+

属性å¯ä»¥å®šä¹‰ä¸ºåªè¯»æˆ–者å¯è¯»å†™çš„。åªè¯»çš„属性åªèƒ½åœ¨åˆ›å»ºå¯¹è±¡çš„æ—¶å€™è¢«èµ‹å€¼ï¼Œè€Œå¯ è¯»å†™çš„å±žæ€§åœ¨ä»»ä½•æ—¶å€™éƒ½èƒ½å¤Ÿæ›´æ”¹ã€‚

+

属性的值也å¯ä»¥æ˜¯å¦å¤–一个对象。比如,File ç±»å¯ä»¥è¿”回一个 DateTime 对 象代表其最åŽä¿®æ”¹æ—¶é—´ï¼Œè€Œä¸æ˜¯è¿”回数字。

+

类也å¯ä»¥æ²¡æœ‰ä»»ä½•å…¬å¼€çš„å¯è®¾ç½®çš„属性。ä¸æ˜¯æ¯ä¸€ä¸ªç±»éƒ½æœ‰å±žæ€§å’Œæ–¹æ³•ã€‚

+

多æ€

+

多æ€是æè¿°æ¥è‡ªä¸åŒç±»çš„对象公用一个接å£çš„说法。比如,File å’Œ WebPage 类都å¯ä»¥æœ‰ print_content() 方法。对于ä¸åŒçš„类,调用这个方法 的输出å¯èƒ½ä¸åŒï¼Œä½†å®ƒä»¬æœ‰é€šç”¨çš„接å£ã€‚

+

尽管在很多方é¢ï¼Œè¿™ä¸¤ä¸ªç±»éƒ½ä¸å°½ç›¸åŒï¼Œä½†å¯¹äºŽ print_content 方法æ¥è¯´ï¼Œä»–们 是一样的。这æ„味ç€æˆ‘们å¯ä»¥åœ¨ä»»ä¸€ç±»çš„对象上调用这个 print_content 方法, 而我们都ä¸éœ€è¦çŸ¥é“对象属于哪个类!

+

多æ€æ˜¯é¢å‘对象设计的关键概念之一。

+

继承

+

继承可以让你创建已ç»å­˜åœ¨çš„类的一个特殊版本。继承创建的新类能够å¤ç”¨åŽŸ æ¥ç±»çš„方法和属性。

+

比如,我们å¯ä»¥åˆ›å»ºä¸€ä¸ª File::MP3 类,这个类从 File 继承而æ¥ã€‚ File::MP3 是 File 的一个更加具体的版本。所有的 mp3 éƒ½æ˜¯æ–‡ä»¶ï¼Œä½†ä¸ æ˜¯æ‰€æœ‰çš„æ–‡ä»¶éƒ½æ˜¯ mp3。

+

我们ç»å¸¸æŠŠç»§æ‰¿å…³ç³»ç§°ä¸º父-å­或者超ç±»/å­ç±»关系。有时候我们说å­ç±»æ˜¯ä¸€ 个父类(比如 File::MP3 类是一个 File 类)。

+

File 是 File::MP3 的超类,而 File::MP3 是 FILE çš„å­ç±»ã€‚

+
  package File::MP3;
+
+  use parent 'File';
+

parent 模å—是 perl 让你定义继承关系的诸多方法之一。

+

Perl å…许多é‡ç»§æ‰¿ï¼Œè¿™æ„味ç€ä¸€ä¸ªç±»å¯ä»¥ç»§æ‰¿è‡ªå¤šä¸ªçˆ¶ç±»ã€‚尽管这是å¯èƒ½çš„,但我们强烈 å对这样åšã€‚通常,你å¯ä»¥ä½¿ç”¨角色(roles)来åšåˆ°ç”¨å¤šé‡ç»§æ‰¿èƒ½åšåˆ°çš„所有事情 ,而且åšæ³•è¿˜æ›´åŠ æ¸…晰。

+

注æ„对一个给定类,给它定义多个å­ç±»æ²¡æœ‰ä»€ä¹ˆå…³ç³»ï¼Œè¿™æ˜¯é€šç”¨ä¸”安全的åšæ³•ã€‚比 如,我们å¯ä»¥ç¬¬ä¸€ File::MP3::FixedBitrate å’Œ File::MP3::VariableBitrate 类,用æ¥åŒºåˆ†ä¸åŒç±»åˆ«çš„ mp3 文件。

+

方法é‡è½½å’Œæ–¹æ³•è§£æž

+

继承å…许两个类共享代ç ã€‚默认情况下,父类的所有方法都能在å­ç±»ä¸­ä½¿ç”¨ã€‚å­ç±» å¯ä»¥æ供它自己的实现æ¥重è½½父类的方法。比如,如果我们有一个 File::MP3 对象,它有从 File 而æ¥çš„ print_info() 方法。

+
  my $cage = File::MP3->new(
+      path          => 'mp3s/My-Body-Is-a-Cage.mp3',
+      content       => $mp3_data,
+      last_mod_time => 1304974868,
+      title         => 'My Body Is a Cage',
+  );
+
+  $cage->print_info;
+  # The file is at mp3s/My-Body-Is-a-Cage.mp3
+

如æžœæˆ‘ä»¬å¸Œæœ›èƒ½å¤Ÿæ‰“å° mp3 çš„å字,那么å¯ä»¥é‡è½½è¿™ä¸ªæ–¹æ³•ã€‚

+
  package File::MP3;
+
+  use parent 'File';
+
+  sub print_info {
+      my $self = shift;
+
+      print "This file is at ", $self->path, "\n";
+      print "Its title is ", $self->title, "\n";
+  }
+
+  $cage->print_info;
+  # The file is at mp3s/My-Body-Is-a-Cage.mp3
+  # Its title is My Body Is a Cage
+

决定使用哪个方法的过程å«åš方法解æž。 perl 在这里所åšçš„是:先查看对象的 所属类(这里是 File::MP3),如果类定义了这个方法,那么调用这个类的版本 。å¦è€…,perl 查看æ¯ä¸ªçˆ¶ç±»ã€‚对于 File::MP3,它的父类åªæœ‰ File。如果 File::MP3 没有定义这个方法,而 File 定义了,那么 perl 就会调用 File 里é¢çš„定义。

+

如æžœ File 继承自 DataSource,而 DataSource 继承自 Thing,那么 有必è¦çš„è¯ï¼Œperl 会“æºç€ç»§æ‰¿é“¾è‡ªä¸‹è€Œä¸Šâ€çš„查找方法定义。

+

可以明确的在å­ç±»ä¸­è°ƒç”¨çˆ¶ç±»çš„方法。

+
  package File::MP3;
+
+  use parent 'File';
+
+  sub print_info {
+      my $self = shift;
+
+      $self->SUPER::print_info();
+      print "Its title is ", $self->title, "\n";
+  }
+

SUPER:: 部分告诉 perl ,在 File::MP3 继承链中查找 print_info() 方 法。当在父类中找到了这个方法,则调用之。

+

之å‰æˆ‘们æ到了多é‡ç»§æ‰¿ã€‚它的主è¦é—®é¢˜å°±æ˜¯ä½¿æ–¹æ³•è§£æžå˜å¾—éžå¸¸å¤æ‚。更多细节 å¯ä»¥æŸ¥é˜… "perl obj"

+

封装

+

封装的ç†å¿µæ˜¯æ¯ä¸ªå¯¹è±¡éƒ½æ˜¯ä¸é€æ˜Žçš„。当其他开å‘人员使用你的类时,他们 ä¸éœ€è¦çŸ¥é“这个类是如何实现的,而åªéœ€è¦çŸ¥é“它åšä»€ä¹ˆå°±å¯ä»¥äº†ã€‚

+

封装在许多方é¢éƒ½æ˜¯éžå¸¸é‡è¦çš„。首先,它å…许你将公用接å£å’Œå†…部实现分开。这 æ„味ç€ä½ èƒ½åœ¨ä¿®æ”¹å®žçŽ°çš„åŒæ—¶ä¸ç ´å接å£ã€‚

+

其次,如果很好的å°è£…了类,继承也将å˜å¾—更加简å•ã€‚ç†æƒ³æƒ…况是,å­ç±»ä½¿ç”¨å’Œçˆ¶ 类相åŒçš„接å£æ¥è®¿é—®å¯¹è±¡æ•°æ®ã€‚实际上,有时候继承会破åå°è£…,但好的接å£ä¼šå‡ å°‘è¿™ç§ç ´å。

+

之å‰æˆ‘们æ到大部分 perl 的对象都是用哈希实现的。å°è£…的原则告诉我们ä¸åº”ä¾èµ– 于此,而应该使用存å–器æ¥èŽ·å¾—哈希中的数æ®ã€‚我们接下æ¥æŽ¨è的对象系统都能自 动生æˆå­˜å–器。如果你使用它们之中的任æ„一个,你永远ä¸éœ€è¦ä½¿ç”¨å“ˆå¸Œæ¥è®¿é—®å¯¹ 象。

+

组åˆ

+

在é¢å‘对象的代ç ä¸­ï¼Œæˆ‘们ç»å¸¸èƒ½çœ‹åˆ°ä¸€ä¸ªå¯¹è±¡æŒ‡å‘å¦å¤–一个对象,这å«åšå¯¹è±¡ 组åˆ,或者有一个关系。

+

之å‰æˆ‘们æ到 File 类的 last_mod_time 方法能够返回一个 DateTime 对 象。这就是一个对象组åˆçš„例å­ã€‚我们也å¯ä»¥æ›´è¿›ä¸€æ­¥ï¼Œè®© path å’Œ content å­˜å–器也返回对象。那么 File 就和许多其他的对象进行了组åˆã€‚

+

角色 Roles

+

角色是一个类“åšçš„事情â€ï¼Œè€Œä¸æ˜¯ç±»æ˜¯ä»€ä¹ˆã€‚对 perl æ¥è¯´ï¼Œè§’色是一个相对较 新,åŒæ—¶ä¹Ÿå¾ˆæµè¡Œçš„概念。角色应用于类。有时我们说类消耗角色。

+

角色是继承之外,æ供多æ€æ€§çš„å¦ä¸€ç§é€‰æ‹©ã€‚å‡è®¾æˆ‘们有两个类,Radio å’Œ Computer。这两ç§ç‰©ä½“都有开关键,我们想在类定义中为之建立模型。

+

我们å¯ä»¥è®©ä¸¤ä¸ªç±»éƒ½ç»§æ‰¿è‡ªåŒä¸€çˆ¶ç±»ï¼Œæ¯”如 Machine,但ä¸æ˜¯æ‰€æœ‰çš„机器都有开 关键。我们也å¯ä»¥å»ºç«‹ä¸€ä¸ªå« HasOnOffSwitch 的父类,但这也太文绉绉了。 Radio å’Œ Computers ä¸æ˜¯è¿™ç§çˆ¶ç±»çš„特殊体。这个父类定义得有点滑稽。

+

这就是角色所适åˆçš„地方。此时建立一个 HasOnOffSwitch 角色并将之应用于类 显得更加åˆç†ã€‚这个角色å¯ä»¥å®šä¹‰å¦‚ turn_on() å’Œ turn_off() ä¹‹ç±»çš„æŽ¥å£ ã€‚

+

Perl 并没有关于角色的内置接å£ã€‚过去,人们都åªèƒ½åˆ«æ— é€‰æ‹©çš„使用多é‡ç»§æ‰¿ã€‚而 现在, CPAN 上有许多模å—å¯ä»¥è®©ä½ ä½¿ç”¨è§’色。

+

什么时候使用 OO

+

面å‘对象并ä¸æ˜¯æ‰€æœ‰é—®é¢˜çš„最好解决方案。在Perl 最佳实践(copyright 2004, Published by O'Reilly Media, Inc.)中,Damian Conway æ供了一个决定OO æ˜¯å¦ æ˜¯è§£å†³ä½ çš„é—®é¢˜çš„æœ€å¥½æ–¹æ¡ˆçš„åˆ—è¡¨ã€‚

+
    +
  • 在设计的系统éžå¸¸åºžå¤§ï¼Œæˆ–者å¯èƒ½å˜å¾—庞大。
  • +
  • 数æ®å¯ä»¥èšåˆæˆä¸€ä¸ªæ˜Žæ˜¾çš„结构,特别是æ¯ä¸ªèšåˆä¸­æœ‰å¤§é‡æ•°æ®çš„时候。
  • +
  • 各ç§ç±»åž‹çš„æ•°æ®ä¼šå½¢æˆè‡ªç„¶çš„层次,让继承和多æ€çš„使用更为容易。
  • +
  • 你有一些数æ®ï¼Œè®¸å¤šä¸åŒçš„è¿ç®—都会应用在那些数æ®ä¸Šé¢ã€‚
  • +
  • 你必须对一些相关类型的数æ®åšä¸€äº›ç›¸åŒçš„通用è¿ç®—,但是会根æ®è¿ç®—所应用于特 定的数æ®ç±»åž‹è€Œæœ‰äº›ç»†å¾®çš„差异。
  • +
  • 你å¯èƒ½æ—¥åŽè¦å¢žåŠ æ–°çš„æ•°æ®ç±»åž‹ã€‚
  • +
  • 数æ®ä¹‹é—´çš„交互最好以è¿ç®—符表示
  • +
  • 系统中个别组件的时间å¯èƒ½éšæ—¶é—´è€Œæ”¹å˜
  • +
  • 系统设计已ç»æ˜¯é¢å‘对象的
  • +
  • 有很多其他程åºå‘˜ä¼šä½¿ç”¨ä½ çš„代ç æ¨¡å—
  • +
+

perl OO 系统

+

就åƒå‰é¢æ‰€è¯´çš„一样,perl 内置的 OO 系统éžå¸¸å°å·§ï¼Œä¹Ÿç›¸å½“çµæ´»ã€‚这些年æ¥ï¼Œåœ¨ perl 的内置系统上é¢ï¼Œäººä»¬å¼€å‘了许多高级系统,用以æ供更多的特性和便利。

+

我们强烈推è你使用这些系统中的一个。它们之中å³ä½¿æ˜¯æœ€è½»å·§çš„实现都能简化许 多é‡å¤å·¥ä½œã€‚没有任何ç†ç”±ä»Žé›¶å¼€å§‹ç”¨ perl 构建你的类。

+

如果你对这些系统的内部实现感兴趣,请å‚阅 perlobj

+

Moose

+

Moose自称为“perl 5çš„åŽçŽ°ä»£å¯¹è±¡ç³»ç»Ÿâ€ã€‚ä¸è¦è¢«å“到,“åŽçŽ°ä»£â€ä¸€è¯å‡ºçŽ° 在这里,åªæ˜¯å¯¹ Larry å°† perl 称作“第一ç§åŽçŽ°ä»£è®¡ç®—机语言â€çš„呼应。

+

Moose提供了一个完全而现代化的 OO 系统。对它影å“最大的是 Common Lisp çš„ é¢å‘对象系统,åŒæ—¶å®ƒä¹Ÿå€Ÿé‰´äº† Smalltalk 和许多其他编程语言的ç†å¿µã€‚Moose ç”± Stevan Little 创建,并从他对 perl 6 OO 的设计工作中获益良多。

+

这是我们使用 Moose çš„ File ç±»

+
  package File;
+  use Moose;
+
+  has path          => ( is => 'ro' );
+  has content       => ( is => 'ro' );
+  has last_mod_time => ( is => 'ro' );
+
+  sub print_info {
+      my $self = shift;
+
+      print "This file is at ", $self->path, "\n";
+  }
+

Moose æ供了许多特性:

+
    +
  • Declarative sugar
  • +
  • 声明å¼çš„语法糖

    Moose提供了一层声明å¼çš„语法糖,用æ¥å®šä¹‰ç±»ã€‚这些语法糖åªæ˜¯ä¸€ç³»åˆ—导出的函 数,它们å¯ä»¥ä½¿å®šä¹‰ä½ çš„类的工作å˜å¾—更加简å•å’Œæ›´å…·å¯ç§»æ¤æ€§ã€‚ä½ å¯ä»¥æè¿°ä½ çš„ç±» 是什么,而ä¸ç”¨åŽ»å‘Šè¯‰ perl 怎样实现它。

    has() å­å‡½æ•°å®šä¹‰äº†ä¸€ä¸ªå±žæ€§ï¼ŒMoose 会自动为其创建存å–器。它还帮你创建了 new() 方法。这个构造器知é“你所定义的属性,所以你能够在创建一个 File 对象时给它们赋值。

  • +
  • + 内置角色 +

    Moose 让你åƒå®šä¹‰ç±»ä¸€æ ·å®šä¹‰è§’色

    +
      package HasOnOfSwitch;
    +  use Moose::Role;
    +
    +  has is_on => (
    +      is  => 'rw',
    +      isa => 'Bool',
    +  );
    +
    +  sub turn_on {
    +      my $self = shift;
    +      $self->is_on(1);
    +  }
    +
    +  sub turn_off {
    +      my $self = shift;
    +      $self->is_on(0);
    +  }
    +
  • +
  • 一个å°åž‹çš„类型系统

    在上é¢çš„例å­ä¸­ï¼Œåˆ›å»º is_on 属性的时候,我们给 has() 传递了å‚æ•° isa => 'Bool'。这是在告诉 Moose,这个属性必须是一个布尔值。如果我们 给它设置éžæ³•å€¼ï¼Œä»£ç å°†ä¼šæŠ›å‡ºé”™è¯¯ã€‚

  • +
  • 完全的内çœå’ŒæŽ§åˆ¶æœºåˆ¶

    Perl 的内置内çœç‰¹æ€§åŠå…¶å¾®å°ã€‚Moose 在它之上,为你的类建立了一个完全的内 çœå±‚,使得你å¯ä»¥é—®è¯¸å¦‚“File 类实现了哪些方法?â€ä¹‹ç±»çš„问题。它还å¯ä»¥è®©ä½  éšå¿ƒæ‰€æ¬²çš„修改你的类。

  • +
  • 自宿主(Self-hosted)å’Œå¯æ‰©å±•æ€§

    Moose ä½¿ç”¨è‡ªå·±çš„å†…çœ API æ述自己。除了这是一个很酷的技巧外,它还æ„å‘³ç€ ä½ å¯ä»¥ç”¨ Moose æ¥æ‰©å±• Moose

  • +
  • 丰富的生æ€ç³»ç»Ÿ

    在 CPAN 上的MooseX 命å空间下,有一个关于 Moose 扩展的丰富的生æ€ç³»ç»Ÿã€‚此外,CPAN 上很多模å—å·² ç»åœ¨ä½¿ç”¨ Moose,æ供了许多å¯ä¾›å­¦ä¹ çš„例å­ã€‚

  • +
  • 更多特性

    Moose 是一个éžå¸¸å¼ºå¤§çš„工具,我们ä¸èƒ½åœ¨è¿™é‡Œä»‹ç»å®ƒå…¨éƒ¨çš„特性。我们鼓励你 从Moose::Manual开始,通 过阅读 Moose 的文档æ¥å­¦ä¹ å®ƒï¼Œ

  • +
+

当然,Moose 也并ä¸å®Œç¾Žã€‚

+

Moose 会使你的代ç è½½å…¥å˜æ…¢ã€‚Moose ä¸æ˜¯ä¸€ä¸ªå°åž‹ç³»ç»Ÿï¼Œå½“你定义你的类时,它åšäº†大é‡代ç ç”Ÿæˆå·¥ä½œã€‚è¿™æ„味ç€ä½  的代ç åœ¨è¿è¡ŒæœŸé—´èƒ½å°½å¯èƒ½çš„快,但在你的模å—第一次被载入时,必须付出一些时间 代价。

+

这个载入时间在å¯åŠ¨é€Ÿåº¦é‡è¦çš„时候会æˆä¸ºä¸€ä¸ªé—®é¢˜ã€‚比如命令行脚本,或者必须 在æ¯æ¬¡æ‰§è¡Œéƒ½è¢«è½½å…¥çš„纯 CGI 脚本。

+

不过先别慌,许多人的确在写命令行工具和其他对å¯åŠ¨æ—¶é—´æ•æ„Ÿçš„代ç ä¸­ä½¿ç”¨äº† Moose。我们鼓励你先试用一下它,然åŽå†è€ƒè™‘å¯åŠ¨é€Ÿåº¦çš„问题。

+

同æ—¶ Moose 还有很多其他模å—çš„ä¾èµ–关系,其中大部分都是å°åž‹çš„独立模å—,还 有一部分是为 Moose 而写的。Moose 本身,以åŠå®ƒçš„一些ä¾èµ–模å—需è¦ç”¨åˆ°ç¼–译器。如果你想将你的软件安装在一个没有 编译器的系统上é¢ï¼Œæˆ–者有任何依赖关系都是问题,那么 Moose å¯èƒ½ä¸é€‚åˆ ä½ ã€‚

+

Mouse

+

如果你使用了 Moose 之åŽï¼Œå‘现这些问题之一阻止你继续使用它,我们建议你接 下æ¥è€ƒè™‘一下 MouseMouse 用一个更简å•çš„包,实现了 Moose 功能的一 个å­é›†ã€‚对于它所实现的所有特性,其接å£å’Œ Moose 是完全相åŒçš„,è¿™æ„味 ç€ä½ å¯ä»¥éžå¸¸å®¹æ˜“的从 Moose è¿ç§»åˆ° Mouse

+

Mouse 没有实现大部分 Moose 的内çœæŽ¥å£ï¼Œæ‰€ä»¥åœ¨è½½å…¥ä½ çš„模å—时,它的速 度更快。åŒæ—¶ï¼Œå®ƒçš„所有ä¾èµ–模å—都由 perl 核心æ供,且ä¸éœ€è¦ç¼–译器就能è¿è¡Œã€‚ 如果你有编译器,那么Mouse 会用它æ¥ç¼–译一些代ç ï¼Œä»Žè€ŒåŠ å¿«è¿è¡Œé€Ÿåº¦ã€‚

+

最åŽï¼Œå®ƒè¿˜åŒ…å«äº†ä¸€ä¸ª Mouse::Tiny 模å—,这个模å—将大部分 Mouse 特性打 包到了一个文件里é¢ã€‚把这个文件拷è´åˆ°ä½ åº”用的库目录,你å¯ä»¥è½»æ˜“打包你的应用 。

+

Moose 的作者希望通过充分改进 Moose,使 Mouse 终有一天能够过时,但 现在 Mouse ä»ç„¶æ供了除 Moose 之外的一个有价值的选择。

+

Class::Accessor

+

Class::Accessor 完全和 Moose 相å。它æ供了很少的特性,也ä¸æ˜¯è‡ªå®¿ä¸» 的。

+

但它éžå¸¸ç®€å•ï¼Œå®Œå…¨ç”± perl 实现,没有éžæ ¸å¿ƒä¾èµ–,åŒæ—¶è¿˜æ供了“类 Mooseâ€çš„ 借å£ã€‚

+

尽管åšçš„ä¸å¤šï¼Œå®ƒä»ç„¶æ¯”你从头开始写你的类好。

+

这是用 Class::Accessor 实现的 File 类:

+
  package File;
+  use Class::Accessor 'antlers';
+
+  has path          => ( is => 'ro' );
+  has content       => ( is => 'ro' );
+  has last_mod_time => ( is => 'ro' );
+
+  sub print_info {
+      my $self = shift;
+
+      print "This file is at ", $self->path, "\n";
+  }
+

antlers 导入符告诉 Class::Accessor 我们想用类 Moose 的语法æ¥å®šä¹‰ 属性。你唯一å¯ä»¥ä¼ ç»™ has çš„å‚数是 is。当你使用 Class::Accessor æ—¶ ,我推è你使用类 Moose 的语法,这æ„味ç€å½“ä½ å°†æ¥å†³å®šä½¿ç”¨ Moose æ—¶ï¼Œä½ å¯ ä»¥æ›´å¹³æ»‘çš„å‡çº§ã€‚

+

Moose 一样,Class::Accessor 为类自动创建构造器和存å–器。

+

Object::Tiny

+

最åŽä»‹ç» Object::Tiny。这个模å—就如它的å字,完全没有ä¾èµ–关系且借å£åŠå…¶ 简å•ã€‚但我们ä»ç„¶è®¤ä¸ºæ¯”起自己写你的 OO 代ç ï¼Œä½¿ç”¨è¿™ä¸ªæ¨¡å—更加容易。

+

再一次,这是我们的 File 类:

+
  package File;
+  use Object::Tiny qw( path content last_mod_time );
+
+  sub print_info {
+      my $self = shift;
+
+      print "This file is at ", $self->path, "\n";
+  }
+

这就足够了!

+

使用 Object::Tiny,所有的存å–器都是åªè¯»çš„。它为你类生æˆæž„造器,也为你定 义的属性生æˆå­˜å–器。

+

Role::Tiny

+

我们å‰é¢æ过,角色æ供了继承之外的其他选择,但 perl 没有内置的角色支æŒã€‚如 果你选择使用 Moose,它æ供了一个æˆç†Ÿçš„角色实现。如果你使用其他我们推èçš„OO 模å—,你ä»ç„¶å¯ä»¥é€šè¿‡ Role::Tiny 使用角色。

+

Role::Tiny æ供了一些Moose 角色系统的特性,但它更加å°å·§ã€‚值得注æ„的是, 它ä¸æ”¯æŒä»»ä½•å±žæ€§å®šä¹‰ï¼Œæ‰€ä»¥ä½ å¿…须手动定义它们。但它任然å分有用,并且和 Class::Accessor 或 Object::Tiny 在一起工作得很好。

+

OO 系统总结

+

这是关于我们æ到的模å—的一个简å•å›žé¡¾

+
    +
  • Moose

    Moose 是最好的选择。它æ供了许多特性,强大的生æ€ç³»ç»Ÿï¼Œå¤§é‡çš„用户基础。 我们也简å•çš„æ到了 Mouse,它是 Moose 的简化版,也是当 Moose ä¸é€‚åˆäºŽä½  的应用的时候的一个åˆç†é€‰æ‹©ã€‚

  • +
  • Class::Accessor

    Class::Accessor åšå¾—比 Moose 少许多,如果你å‘现 Moose 太é‡é‡çº§äº†ï¼Œå®ƒ 是一个很好的选择。这个模å—å·²ç»å­˜åœ¨äº†ç›¸å½“长时间,而且也通过了很好的测试。它 还æ供了一个轻é‡çš„ Moose 兼容接å£ï¼Œè¿™ä½¿å¾—从Class::Accessor è¿ç§»åˆ° Moose éžå¸¸ç®€å•ã€‚

  • +
  • Object::Tiny

    Object::Tiny 是最åŽçš„选择。它没有任何ä¾èµ–,ä¸éœ€è¦å­¦ä¹ ä»»ä½•è¯­æ³•ã€‚当你需 è¦ä¸€ä¸ªè¶…级简å•çš„环境,并且ä¸éœ€è¦è€ƒè™‘细节的将一些东西æåˆèµ·æ¥æ—¶ï¼Œå®ƒæ˜¯ä¸€ä¸ª ä¸é”™çš„选择。

  • +
  • Role::Tiny

    如果你å‘现自己在考虑多é‡ç»§æ‰¿çš„时候,å¯ä»¥ç»„åˆä½¿ç”¨ Role::Tiny å’Œ Class::Accessor 或 Object::Tiny。如果你使用 Moose,它æ供了自己的 角色实现。

  • +
+

其ä»– OO 系统

+

除了这里æ到的 OO 系统外,CPAN 上还有æˆå †çš„相关模å—。当你在使用别人的代ç æ—¶ ,很有å¯èƒ½å°±ä¼šç¢°åˆ°å®ƒä»¬ã€‚

+

其次,还有许多代ç ä½¿ç”¨ perl 的内置 OO 特性“手动â€çš„实现它自己的 OO。如果你 需è¦ç»´æŠ¤è¿™ç§ä»£ç ï¼Œä½ å¿…须阅读 perlobj,ç†è§£ perl 的内置 OO 是如何工作的 。

+

总结

+

就åƒæˆ‘们å‰é¢æ‰€è¯´ï¼Œperl è½»é‡çš„ OO 系统使得 CPAN 上é¢å­˜åœ¨å¤§é‡çš„ OO 模å—。尽管你 ä»ç„¶å¯ä»¥é€‰æ‹©è‡ªå·±æ‰‹åŠ¨ç¼–写你的类,但在现在,2011,你没有任何ç†ç”±è¦åŽ»é‚£æ ·åšã€‚

+

对于å°é¡¹ç›®ï¼ŒObject::Tiny å’Œ Class::Accessor 都æ供了一个轻é‡çš„对象系 统,能够解决你的基本问题。

+

对于更大的项目,Moose æ供了丰富的特性,使你能够关注在业务逻辑层é¢ä¸Šã€‚

+

我们鼓励你使用并测试这些模å—,MooseClass::AccessorObject::Tiny,然åŽå†å†³å®šå“ªä¸ªé€‚åˆäºŽä½ ã€‚

+

TRANSLATORS

+

Woosley Xu woosley.xu@gmail.com

+ + diff --git a/POD/CN_html/perlopentut.html b/POD/CN_html/perlopentut.html new file mode 100644 index 0000000..12d81d4 --- /dev/null +++ b/POD/CN_html/perlopentut.html @@ -0,0 +1,424 @@ + + + + perlopentut + + + + +

NAME

+

perlopentut - Perl 中 open 的指å—

+

DESCRIPTION

+

Perl 有两ç§ç®€å•çš„内建的方法打开文件:简便的 shell 方法和精确的 C 方法。 shell 的方法åˆåˆ†ä¸ºä¸¤ä¸ªå‚æ•°çš„å½¢å¼å’Œä¸‰ä¸ªå‚æ•°çš„å½¢å¼ï¼Œè¿™ä¸¤ç§å½¢å¼å¯¹äºŽæ–‡ä»¶å 的处ç†æœ‰ä¸åŒçš„语义。你å¯ä»¥è‡ªç”±é€‰æ‹©ã€‚

+

Open à la shell

+

Perl çš„ open 函数是模仿 shell 工作时的命令行é‡å®šå‘æ¥è®¾è®¡çš„。这是 shell 中的一些基本例å­ï¼š

+
    $ myprogram file1 file2 file3
+    $ myprogram    <  inputfile
+    $ myprogram    >  outputfile
+    $ myprogram    >> outputfile
+    $ myprogram    |  otherprogram 
+    $ otherprogram |  myprogram
+

这是一些高级的例å­ï¼š

+
    $ otherprogram      | myprogram f1 - f2
+    $ otherprogram 2>&1 | myprogram -
+    $ myprogram     <&3
+    $ myprogram     >&4
+

习惯构建上é¢è¿™äº›çš„程åºå‘˜å¯ä»¥å¾ˆå®¹æ˜“看到 Perl 使用几乎和 shell 相åŒçš„语 法支æŒè¿™äº›ç±»ä¼¼çš„结构。

+

简å•çš„ Open

+

open 函数使用两个å‚数:一个是文件å¥æŸ„,å¦ä¸€ä¸ªæ˜¯æ述怎样打开和è¦æ‰“ 开什么的字符串。当æˆåŠŸæ—¶ï¼Œopen 返回值为真;当失败时,返回值为å‡ï¼Œå¹¶ 且设置特殊å˜é‡ $! æ¥å映系统错误。如果第一个å‚æ•°å³æ–‡ä»¶å¥æŸ„å·²ç»æ‰“å¼€ 过,open 会先把它关掉。

+

例如:

+
    open(INFO,      "datafile") || die("can't open datafile: $!");
+    open(INFO,   "<  datafile") || die("can't open datafile: $!");
+    open(RESULTS,">  runstats") || die("can't open runstats: $!");
+    open(LOG,    ">> logfile ") || die("can't open logfile:  $!");
+

如果你喜欢少用标点,å¯ä»¥è¿™æ ·å†™ï¼š

+
    open INFO,   "<  datafile"  or die "can't open datafile: $!";
+    open RESULTS,">  runstats"  or die "can't open runstats: $!";
+    open LOG,    ">> logfile "  or die "can't open logfile:  $!";
+

有几点需è¦æ³¨æ„。一是,开头的å°äºŽå·ä¸æ˜¯å¿…须的,如果çœç•¥ï¼ŒPerl å‡å®šä½ è¦ 以å¯è¯»çš„æ–¹å¼æ‰“开文件。

+

二是在第一个例å­ä¸­ä½¿ç”¨ || 逻辑è¿ç®—符,而第二个例å­ä¸­ä½¿ç”¨ä¼˜å…ˆçº§æ›´ä½Ž çš„ or。如果在åŽä¸€ä¸ªä¾‹å­ä¸­ä½¿ç”¨ || 则等效于:

+
    open INFO, ( "<  datafile"  || die "can't open datafile: $!" );
+

这肯定ä¸æ˜¯ä½ æƒ³è¦çš„。

+

另一个值得注æ„的是,和在 shell 中一样,文件åå‰é¢æˆ–者åŽé¢çš„空格都被忽 略了。这很好,因为你ä¸æ„¿æ„这些会有ä¸åŒå§ï¼š

+
    open INFO,   "<datafile"   
+    open INFO,   "< datafile" 
+    open INFO,   "<  datafile"
+

当你从å¦ä¸€ä¸ªæ–‡ä»¶ä¸­è¯»å–文件å,å´åœ¨æ‰“开之å‰å¿˜è®°åŽ»é™¤ä¸¤ç«¯çš„空格,忽略文件 å两端的空格å¯ä»¥é¿å…è¿™ç§æƒ…况å‘生:

+
    $filename = <INFO>;         # oops, \n still there
+    open(EXTRA, "< $filename") || die "can't open $filename: $!";
+

这ä¸æ˜¯ä¸€ä¸ª bug,而是一个特性。因为 open 模仿 shell 使用é‡å®šå‘箭头指 定怎样打开文件的风格,所以也应当åŒæ ·å¿½ç•¥æ–‡ä»¶å两端的空格。对于访问文件åä¸ç¬¦åˆ 规定的文件,å‚è§ "Dispelling the Dweomer"

+

也有三个å‚数版本的 open,è¿™å¯ä»¥è®©ä½ åŠ å…¥ç‰¹æ®Šçš„é‡å®šå‘字符到å‚数中:

+
    open( INFO, ">", $datafile ) || die "Can't create $datafile: $!";
+

在è¿™ç§æƒ…况下,打开的文件å是 $datafile 这个字符串。这样你ä¸ç”¨æ‹…心 $datafile 中å«æœ‰å½±å“打开模å¼çš„字符,或者在两个å‚数版本中忽略文件å 两端的空格。而且ä¸è¿›è¡Œä¸å¿…è¦çš„字符串内æ’。

+

间接文件å¥æŸ„

+

open 的第一个å‚æ•°å¯ä»¥æ˜¯ä¸€ä¸ªæ–‡ä»¶å¥æŸ„的引用。在 Perl 5.6.0 中,如果 å‚数没有åˆå§‹åŒ–,Perl 会自动创建一个文件å¥æŸ„,然åŽå­˜å‚¨åœ¨ç¬¬ä¸€ä¸ªå‚数中, 例如:

+
    open( my $in, $infile )   or die "Couldn't read $infile: $!";
+    while ( <$in> ) {
+        # do something with $_
+    }
+    close $in;
+

间接文件å¥æŸ„å¯ä»¥ä½¿å字空间的管ç†æ›´ç®€å•ã€‚由于文件å¥æŸ„对于当å‰åŒ…是全局 的,两个函数试图åŒæ—¶æ‰“å¼€ INFILE 会导致冲çªã€‚如果两个函数使用间接文 件å¥æŸ„比如 my $infile,则ä¸ä¼šå‘生冲çªï¼Œä¹Ÿä¸ç”¨æ‹…心以åŽä¼šå‘生冲çªã€‚

+

还有一个方便之处是当è¿è¡Œåˆ°ä½œç”¨åŸŸå¤–或者使用 undefine 时,间接文件å¥æŸ„会 自动关闭。

+
    sub firstline {
+        open( my $in, shift ) && return scalar <$in>;
+        # no close() required
+    }
+

打开管é“

+

在 C 中,当你想用标准 I/O 库打开一个文件时,你è¦ç”¨ fopen 函数,当你 想打开一个管é“时,你è¦ç”¨ popen 函数。但是在 shell 中,你åªæ˜¯ç”¨ä¸åŒ çš„é‡å®šå‘字符。对于 Perl 也是如此。open 的调用方法一样,åªæ˜¯å‚æ•°ä¸åŒäº†ã€‚

+

如果以管é“符å·å¼€å¤´ï¼Œopen å¯åŠ¨ä¸€ä¸ªæ–°çš„命令,打开一个å¯å†™æ–‡ä»¶å¥æŸ„é€šå‘ è¿™ä¸ªå‘½ä»¤ã€‚ä½ å¯ä»¥å‘这个å¥æŸ„中写入内容,而你所写的将出现在这个命令的标准 输出里。例如:

+
    open(PRINTER, "| lpr -Plp1")    || die "can't run lpr: $!";
+    print PRINTER "stuff\n";
+    close(PRINTER)                  || die "can't close lpr: $!";
+

如果末尾的字符是一个管é“时,你å¯åŠ¨ä¸€ä¸ªæ–°çš„命令,打开一个通å‘这个命令的 å¯è¯»æ–‡ä»¶å¥æŸ„。这使得这个命令写入标准输出的内容å¯ä»¥åœ¨ä½ çš„å¥æŸ„中读到的。

+
    open(NET, "netstat -i -n |")    || die "can't fork netstat: $!";
+    while (<NET>) { }               # do something with input
+    close(NET)                      || die "can't close netstat: $!";
+

当你试图打开一个通å‘或者æ¥è‡ªä¸å­˜åœ¨çš„命令的管é“时会å‘ç”Ÿä»€ä¹ˆå‘¢ï¼Ÿå¦‚æžœå¯ èƒ½ï¼ŒPerl 会检测到命令失败,然åŽç…§å¸¸è®¾ç½® $!。但是如果命令中包å«ç‰¹æ®Š çš„ shell 字符,例如 > 或者 *,称为“metacharactersâ€ï¼ŒPerl ä¸ ä¼šç›´æŽ¥æ‰§è¡Œå‘½ä»¤ã€‚å–而代之的是,Perl è¿è¡Œ shell,它æ¥è¯•å›¾è¿è¡Œå‘½ä»¤ã€‚è¿™æ„ å‘³ç€æ˜¯ shell 得到错误指示。在这ç§æƒ…况下,如果 Perl 根本ä¸èƒ½è¿è¡Œ shell,open åªä¼šæŒ‡ç¤ºä¸€ä¸ªé”™è¯¯ã€‚å‚考 "How can I capture STDERR from an external command?" in perlfaq8 了解如何应付这个问题。在 perlipc 中也有回答。

+

如果你想打开åŒå‘管é“,IPC::Open2 å¯ä»¥å¤„ç†ã€‚å‚考 "Biderectional Communication with Another Process" in perlipc

+

负å·æ–‡ä»¶

+

和标准 shell 实用程åºä¸€æ ·ï¼ŒPerl çš„ open 函数对于åªæ˜¯ä¸€ä¸ªè´Ÿå·çš„文件 å的处ç†æ–¹æ³•æ˜¯ç‰¹æ®Šçš„。如果你以å¯è¯»æ–¹å¼æ‰“开负å·ï¼Œå®žé™…上是访问标准输入。 如果以å¯å†™æ–¹å¼æ‰“开,实际上是访问标准输出。

+

如果负å·èƒ½ç”¨ä½œé»˜è®¤çš„输入或者输出,当你打开一个通å‘或者æ¥è‡ªè´Ÿå·çš„管é“会 å‘生什么呢?它会è¿è¡Œä»€ä¹ˆé»˜è®¤çš„命令?仅仅是和你现在è¿è¡Œçš„脚本一样ï¼äº‹å®ž 上在 open 背åŽç§˜å¯†è¿›è¡Œäº†ä¸€æ¬¡ fork。更详细内容请å‚考 "Safe Pipe Opens" in perlipc

+

交å‰è¯»å†™

+

同时指定读和写的访问是å¯ä»¥çš„。你åªè¦åœ¨é‡å®šå‘符å·å‰åŠ ä¸Šä¸€ä¸ªâ€œ+â€å·ã€‚ä½†æ˜¯åŒ åœ¨ shell 中一样,对一个文件使用 less-than 决ä¸ä¼šåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼Œå®ƒä»…ä»… 是打开一个已ç»å­˜åœ¨çš„文件。å¦ä¸€æ–¹é¢ï¼Œä½¿ç”¨ greater-than 总是破å(截短长度为 0)已ç»å­˜åœ¨çš„文件,或者如果没有旧文件的è¯ï¼Œåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ã€‚ Adding a "+" for read-write doesn't affect whether it only works on existing files or always clobbers existing ones.

+
    open(WTMP, "+< /usr/adm/wtmp") 
+        || die "can't open /usr/adm/wtmp: $!";
+
+    open(SCREEN, "+> lkscreen")
+        || die "can't open lkscreen: $!";
+
+    open(LOGFILE, "+>> /var/log/applog"
+        || die "can't open /var/log/applog: $!";
+

第一个ä¸ä¼šåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼Œç¬¬äºŒæ€»æ˜¯ç ´å旧文件。第三个在必è¦æ—¶æ€»ä¼šåˆ›å»ºä¸€ 个新文件而且ä¸ä¼šç ´å旧文件,并å…许你读å–文件任何中的ä½ç½®ï¼Œä½†æ˜¯å†™å…¥çš„内 容总是放到文件末尾。简短的说,第一个比第二个和第三个都è¦å¸¸ç”¨ï¼Œè€ŒåŽè€…几 乎总是错的。(*ä¸æ˜¯å¤ªè‚¯å®š*)(如果你了解 C,Perl çš„ open 中加å·æ˜¯ä»Ž C çš„ fopen(3S) 中演化而æ¥çš„,它也是最终调用这个函数。)

+

事实上,当è¦æ›´æ–°æ–‡ä»¶æ—¶ï¼Œé™¤éžæ˜¯åƒä¸Šé¢ WTMP 的例å­æ“ä½œäºŒè¿›åˆ¶æ–‡ä»¶ï¼Œä½ å¾ˆå¯ èƒ½ä¸ä¼šç”¨è¿™ç§æ–¹æ³•æ¥æ›´æ–°ã€‚而是使用 Perl çš„ -i 选项。下é¢è¿™ä¸ªå‘½ä»¤å°†æ‰€ 有 Cã€C++ å’Œ yacc æºæ–‡ä»¶æˆ–者头文件中的 foo 替æ¢æˆ bar,并把旧版本文件 å加上 “.origâ€åŽç¼€ï¼š

+
    $ perl -i.orig -pe 's/\bfoo\b/bar/g' *.[Cchy]
+

这是更新文本文件的最好方法。更详细内容,请å‚考 perlfaq5 中的第二个问题。 This is a short cut for some renaming games that are really the best way to update textfiles.

+

过滤器

+

open 的一个最普é的用途å¯èƒ½æ˜¯ä½ æ ¹æœ¬æ²¡æœ‰æ³¨æ„到的。当你使用 <ARGV> å¤„ç† ARGV 文件å¥æŸ„时,Perl 实际上是éšå¼çš„对 @ARGV 使用 open。 所以åƒè¿™æ ·è°ƒç”¨ä¸€ä¸ªç¨‹åºï¼š

+
    $ myprogram file1 file2 file3
+

能够打开所有的文件,通过这样一个简å•çš„结构一个一个的处ç†ï¼š

+
    while (<>) {
+        # do something with $_
+    } 
+

如果在循环开始时 @ARGV 还是空列表,Perl å‡å®šä½ æ‰“开一个负å·ï¼Œä¹Ÿå°±æ˜¯æ ‡å‡† è¾“å…¥ã€‚äº‹å®žä¸Šï¼Œåœ¨å¤„ç† <ARGV> 时作为当å‰æ–‡ä»¶çš„ $ARGV 在这ç§æƒ…况下 就是设置为 “-â€ã€‚

+

你最好在开始循环之å‰å¯¹ @ARGV 进行预处ç†æ¥ç¡®ä¿è¿™æ˜¯ä½ æ‰€æƒ³è¦çš„。一个ç†ç”± 是去掉以负å·å¼€å¤´çš„命令行选项。尽管手工æ“作也很简å•ï¼Œä½†æ˜¯æœ€å¥½ä½¿ç”¨ Getopts 模å—:

+
    use Getopt::Std;
+
+    # -v, -D, -o ARG, sets $opt_v, $opt_D, $opt_o
+    getopts("vDo:");            
+
+    # -v, -D, -o ARG, sets $args{v}, $args{D}, $args{o}
+    getopts("vDo:", \%args);    
+

或者使用标准模å—中的 Getopt::Long æ¥å…许命åå‚数:

+
    use Getopt::Long;
+    GetOptions( "verbose"  => \$verbose,        # --verbose
+                "Debug"    => \$debug,          # --Debug
+                "output=s" => \$output );       
+            # --output=somestring or --output somestring
+

另一个预处ç†å‚数的原因是使空的å‚数列表å˜æˆé»˜è®¤ä¸ºå…¨éƒ¨æ–‡ä»¶ï¼š

+
    @ARGV = glob("*") unless @ARGV;
+

你甚至å¯ä»¥è¿‡æ»¤åŽåªå‰©ä¸‹çº¯æ–‡æœ¬æ–‡ä»¶ã€‚This is a bit silent, of course, and you might prefer to mention them on the way.

+
    @ARGV = grep { -f && -T } @ARGV;
+

如果你使用 -n 或者 -p 命令行选项,你应当在 BEGIN{} å—中对 @ARGV 进行修改。

+

记ä½ä¸€ä¸ªæ™®é€šçš„ open 有特殊的性质,它å¯èƒ½è°ƒç”¨ fopen(3S) 也å¯èƒ½è°ƒç”¨ popen(3S),å–决于调用的å‚数。这也是人们称它为“神奇的 openâ€çš„原因。这里有 一个例å­ï¼š

+
    $pwdinfo = `domainname` =~ /^(\(none\))?$/
+                    ? '< /etc/passwd'
+                    : 'ypcat passwd |';
+
+    open(PWD, $pwdinfo)                 
+                or die "can't open $pwdinfo: $!";
+

这使得 open 也充当了过滤器的角色。因为 <ARGV> 的处ç†åŒ…å«äº†é€šå¸¸ çš„ shell 风格的 Perl open ,它包å«äº†æˆ‘们已ç»è¯´åˆ°çš„所有特殊的情况: This sort of thing also comes into play in filter processing. Because <ARGV> processing employs the normal, shell-style Perl open, it respects all the special things we've already seen:

+
    $ myprogram f1 "cmd1|" - f2 "cmd2|" f3 < tmpfile
+

这个程åºå°†ä»Žæ–‡ä»¶ f1,进程 cmd1,标准输入(在这个例å­ä¸­æ˜¯ tmpfile),文件 f2,命令 cmd2 ,最åŽæ˜¯æ–‡ä»¶ f3 中读入。

+

对,这æ„味ç€å¦‚果你的目录下有一个å为“-â€ï¼ˆæˆ–者其它类似å字)的文 件,open ä¸ä¼šæŠŠå®ƒä»¬å½“åšåˆæ³•çš„文件处ç†ã€‚你需è¦ç”¨â€œ./-â€ï¼Œå°±åƒä½¿ç”¨ rm 程åºä¸€æ ·ï¼Œæˆ–者你å¯ä»¥ä½¿ç”¨ä¸‹é¢å°†æ到的 sysopen

+

一个更有趣的应用是将文件或者æŸä¸ªå字转æ¢æˆç®¡é“。例如,用 gzip 自动处 ç† gzipped 或者压缩的文件:

+
    @ARGV = map { /^\.(gz|Z)$/ ? "gzip -dc $_ |" : $_  } @ARGV;
+

或者,如果你在安装 LWP 之åŽæœ‰ GET 程åºï¼Œä½ å¯ä»¥åœ¨é€šè¿‡ URL 获å–之åŽè¿› 行处ç†ï¼š

+
    @ARGV = map { m#^\w+://# ? "GET $_ |" : $_ } @ARGV;
+

所以称为魔术 <ARGV> ä¸æ˜¯å¹³ç™½æ— æ•…的,很贴切,ä¸æ˜¯å—?

+

Open à la C

+

如果你想象 shell 那样简便,Perl çš„ open 无疑是一ç§æ–¹æ³•ã€‚å¦ä¸€æ–¹é¢ï¼Œ 如果你想è¦æ¯” C 中简å•çš„ fopen(3S) 更精确,那么应该看看 Perl çš„ sysopen。这是会直接进行系统调用 open(2)。确实æ„味ç€ç‰µæ¶‰äº†æ›´å¤šï¼Œè¿™æ˜¯ 精确性的代价。 That does mean it's a bit more involved, but that's the price of precision.

+

sysopen 有 3(或者 4)个å‚数:

+
    sysopen HANDLE, PATH, FLAGS, [MASK]
+

HANDLE å‚æ•°æ˜¯åƒ open 中一样文件å¥æŸ„。PATH 是一个åˆæ³•çš„è·¯å¾„ï¼Œè¿™æ˜¯ä¸ ç®¡ greater-than 或者 less-thans 或者管é“或者负å·ï¼Œä¹Ÿä¸å¿½ç•¥ç©ºæ ¼ã€‚å¦‚æžœå‚ æ•°ä¸­æœ‰è¿™äº›ç¬¦å·ï¼Œå°†ä½œä¸ºè·¯å¾„的一部分。FLAG å‚数包å«ä¸€ä¸ªæˆ–者多个从 Fcntl 模å—中è¡ç”Ÿå‡ºæ¥çš„值,它们用ä½è¿ç®—符“|â€è¿žæŽ¥èµ·æ¥ã€‚最åŽä¸€ä¸ªå‚æ•° MASK æ˜¯å¯ é€‰çš„ï¼Œå¦‚æžœä½¿ç”¨çš„è¯ï¼Œå®ƒå’Œç”¨æˆ·å½“å‰çš„ umask 进行与æ“作æ¥å†³å®šåˆ›å»ºçš„文件的 模å¼ã€‚你应当通常都忽略这一项。

+

虽然传统上åªè¯»ã€åªå†™å’Œè¯»å†™çš„值分别为 0ã€1 å’Œ 2,但是在有些系统上ä¸æ˜¯è¿™ 样。所以最好从 Fcntl 模å—中导入相应的常数。它æ供了下é¢çš„标准 flag:

+
    O_RDONLY            Read only
+    O_WRONLY            Write only
+    O_RDWR              Read and write
+    O_CREAT             Create the file if it doesn't exist
+    O_EXCL              Fail if the file already exists
+    O_APPEND            Append to the file
+    O_TRUNC             Truncate the file
+    O_NONBLOCK          Non-blocking access
+

有时在æŸäº›æ“作系统中有一些ä¸å¸¸ç”¨çš„ flag,包括 O_BINARYO_TEXTO_SHLOCKO_EXLOCKO_DEFERO_SYNCO_ASYNCO_DSYNCO_RSYNCO_NOCTTYO_NDELAY å’Œ O_LARGEFILE。 详细情况请查看你的 open(2) 手册页或者相应文档(注æ„:从 Perl 5.6 开始如 æžœå…许的è¯ï¼Œ O_LARGEFILE flag 自动加入到 sysopen() çš„ flag 中,因为 默认是大文件)。

+

这是怎样用 sysopen æ¥æ¨¡æ‹Ÿå‰é¢ç®€å•çš„ open 调用。为了简æ´ï¼Œæˆ‘ä»¬çœ ç•¥äº† || die $! 检验,但是在真正用时你è¦æ€»æ˜¯æ£€æŸ¥è¿”回值。这ä¸æ˜¯å®Œå…¨ç›¸ åŒçš„,因为 open 会去掉两端的空格,但是你应该明白它的æ„æ€ã€‚

+

为了打开一个åªè¯»çš„文件:

+
    open(FH, "< $path");
+    sysopen(FH, $path, O_RDONLY);
+

打开一个åªå†™çš„文件,如果有需è¦çš„è¯ï¼Œåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼Œå¦åˆ™æ¸…空旧文件:

+
    open(FH, "> $path");
+    sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT);
+

打开一个文件,往文件内追加内容,如果有需è¦çš„è¯ï¼Œåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼š

+
    open(FH, ">> $path");
+    sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT);
+

打开一个文件更新内容,这个文件必须已ç»å­˜åœ¨ï¼š

+
    open(FH, "+< $path");
+    sysopen(FH, $path, O_RDWR);
+

这还有一些ä¸èƒ½ç”¨å¸¸è§„çš„ open 而å¯ä»¥ç”± sysopen æ¥å®Œæˆçš„事情。你将看 到这是通过控制第三个å‚æ•° flag 实现。 As you'll see, it's just a matter of controlling the flags in the third argument.

+

打开一个åªå†™æ–‡ä»¶ï¼Œåˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶è€Œä¸”这个文件先å‰ä¸€å®šä¸èƒ½å­˜åœ¨ï¼š

+
    sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT);
+

打开一个文件进行追加内容,这个文件先å‰ä¸€å®šæ˜¯å·²ç»å­˜åœ¨çš„:

+
    sysopen(FH, $path, O_WRONLY | O_APPEND);
+

打开一个文件进行更新,如果有必è¦åˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼š

+
    sysopen(FH, $path, O_RDWR | O_CREAT);
+

打开一个文件进行更新,这个文件先å‰ä¸€å®šæ˜¯å·²ç»å­˜åœ¨çš„:

+
    sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT);
+

以无阻塞方å¼æ‰“开文件,如果在必è¦åˆ›å»ºä¸€ä¸ªæ–°æ–‡ä»¶ï¼š

+
    sysopen(FH, $path, O_WRONLY | O_NONBLOCK | O_CREAT);
+

Permissions à la mode

+

如果你忽略了 sysopen çš„ MASK å‚数,Perl 使用八进制数值 0666ã€‚å¯¹äºŽå¯ æ‰§è¡Œç¨‹åºå’Œç›®å½•ï¼Œé€šå¸¸ MASK 值是 0777,其它是 0666。

+

为什么这样宽æ¾å‘¢ï¼Ÿäº‹å®žä¸Šä¸æ˜¯è¿™æ ·çš„。MASK 将用你当å‰è¿›ç¨‹çš„ umask ä¿® 饰。umask 是一个代表 disabled çš„æƒé™ä½çš„数字,也就是由创建的文件中 ä¸å…许打开的æƒé™ä½ç»„æˆçš„。

+

例如,如果你的 umask 是 027,020 部分将使用户组ä¸èƒ½å†™ï¼Œ007 部分将使 其它用户ä¸èƒ½è¯»ã€å†™å’Œæ‰§è¡Œã€‚在这些æ¡ä»¶ä¸‹ï¼Œä¼ é€’ 0666 ç»™ sysopen 将创建 一个模å¼ä¸º 0640 的文件,因为 0666 & -027 是 0640。

+

你应该尽é‡ä¸ç”¨ sysopen çš„ MASK å‚数。因为这剥夺了你的用户选择新文件 æƒé™çš„自由了。但是对于æ•æ„Ÿæˆ–者éšç§çš„æ•°æ®æ˜¯ä¸€ä¸ªä¾‹å¤–,例如邮件目录〠cookie 文件和内部的临时文件。

+

Obscure Open Tricks

+

Re-Opening Files (dups)

+

有时当你有一个打开的文件å¥æŸ„è¦ï¼Œä½ æƒ³ä½¿å¦ä¸€ä¸ªå¥æŸ„是å‰ä¸€ä¸ªçš„æ‹·è´ã€‚在 shell 中,我们在文件æ述符å‰åŠ ä¸€ä¸ªä¸Žç¬¦å·ï¼ˆâ€˜&’)æ¥é‡å®šå‘。例如,2>&1 使æ述符 2(在 Perl 中是标准错误输出)é‡å®šå‘到æ述符 1(在 Perl 中通常是标准输出)。这在 Perl 中也是相åŒçš„,以与符å·å¼€å¤´çš„文件å,如 果是数字将当作文件æ述符,如果是字符串将当作文件å¥æŸ„。

+
    open(SAVEOUT, ">&SAVEERR") || die "couldn't dup SAVEERR: $!";
+    open(MHCONTEXT, "<&4")     || die "couldn't dup fd4: $!";
+

这æ„味ç€ï¼Œå¦‚果一个函数需è¦ä¸€ä¸ªæ–‡ä»¶å,但是由于你已ç»æ‰“å¼€äº†è¿™ä¸ªæ–‡ä»¶ï¼Œä¸ æƒ³ä¼ é€’ä¸€ä¸ªæ–‡ä»¶å给它,你åªè¦ä¼ é€’一个以与符å·å¼€å¤´çš„文件å¥æŸ„。最好用全称 å½¢å¼çš„å¥æŸ„,防止这个函数是在ä¸åŒçš„包中:

+
    somefunction("&main::LOGFILE");
+

像这样,如果 somefunction() å°†è¦ open 它的å‚数,它会使用已ç»æ‰“开的å¥æŸ„。 这与传递一个å¥æŸ„是ä¸åŒçš„,因为你如果传递一个å¥æŸ„ï¼Œä½ æ ¹æœ¬ä¸ open 这个文 件,而这里你确实给 open 传递了å‚数。

+

如果你有一个 I/O 对象(这是 C++ 程åºå‘˜ä»¬å¼ºçƒˆè¦æ±‚的,诡异新奇的),这就 ä¸èƒ½æ­£å¸¸å·¥ä½œäº†ï¼Œå› ä¸ºåœ¨å¯¹äºŽåŽŸæ¥ Perl 看æ¥è¿™ä¸æ˜¯ä¸€ä¸ªæ–‡ä»¶å¥æŸ„。你è¦ä½¿ç”¨ fileno() æ¥å¾—到它的æ述符,å‡å¦‚å¯ä»¥ï¼š

+
    use IO::Socket;
+    $handle = IO::Socket::INET->new("www.perl.com:80");
+    $fd = $handle->fileno;
+    somefunction("&$fd");  # not an indirect function call
+

如果就用真正的文件å¥æŸ„会更简å•ä¸€äº›ï¼ˆè€Œä¸”显然会更快):

+
    use IO::Socket;
+    local *REMOTE = IO::Socket::INET->new("www.perl.com:80");
+    die "can't connect" unless defined(fileno(REMOTE));
+    somefunction("&main::REMOTE");
+

如果在文件å¥æŸ„或者æ述符之å‰ä¸æ˜¯â€œ&â€è€Œæ˜¯â€œ&=â€ï¼ŒPerl å°†ä¸ä¼šå¯¹è¿™ä¸ªç›¸åŒçš„æ–‡ 件å¥æŸ„用系统调用 dup(2) 创建一个新的æ述符,而是使用 fdopen(3S) 库调用 产生一个对已ç»å­˜åœ¨çš„文件å¥æŸ„的别å。这会å‡å°‘一些系统资æºï¼Œå°½ç®¡çŽ°åœ¨æ¯”较 少关注这个方é¢ã€‚这是一个例å­ï¼š

+
    $fd = $ENV{"MHCONTEXTFD"};
+    open(MHCONTEXT, "<&=$fd")   or die "couldn't fdopen $fd: $!";
+

如果你使用魔术 <ARGV>,你也å¯ä»¥åœ¨å‘½ä»¤è¡Œå‚数中传递类似于 "<&=$MHCONTEXTFD çš„å‚æ•°ç»™ @ARGV,但是从æ¥æ²¡æœ‰è§è¿‡æœ‰äººè¿™æ ·åšã€‚

+

Dispelling the Dweomer

+

Perl 比 Java 等其它语言更åƒä¸€ä¸ª DWIMmer,DWIM 是“按我的æ„æ€åŽ»åšï¼ˆdo what I mean)â€çš„缩写。而且比你想象的还è¦æœ‰é­”力。Perl 是具有强大的魔法 (dweomer,这是一个生僻è¯ï¼Œæ„æ€æ˜¯é­”法)。有时,Perl çš„ DWIMmer æ˜¯åƒ dweomer 一样令人感到舒æœã€‚ Perl is more of a DWIMmer language than something like Java--where DWIM is an acronym for "do what I mean". But this principle sometimes leads to more hidden magic than one knows what to do with. In this way, Perl is also filled with dweomer, an obscure word meaning an enchantment. Sometimes, Perl's DWIMmer is just too much like dweomer for comfort.

+

如果魔术 open 对你æ¥è¯´å¤ªç¥žå¥‡äº†ï¼Œä½ ä¹Ÿä¸å¿…因此使用 sysopen。è¦æ‰“å¼€ 一个文件å中有任æ„奇怪字符的文件,有必è¦ä¿æŠ¤å¥½å¼€å¤´å’Œç»“尾的空格。开头的 空格å¯ä»¥é€šè¿‡åœ¨æ–‡ä»¶åå‰æ’å…¥ "./" ,末尾的空格å¯ä»¥é€šè¿‡åœ¨å­—符串末尾添加 一个 ASCII NUL 字节。

+
    $file =~ s#^(\s)#./$1#;
+    open(FH, "< $file\0")   || die "can't open $file: $!";
+

当然,这里å‡å®šä½ çš„系统点是当å‰å·¥ä½œç›®å½•ï¼Œæ–œçº¿æ˜¯ç›®å½•åˆ†éš”符,而且在åˆæ³•çš„ 文件å中ä¸å…许出现 ASCII NUL。许多系统是éµå®ˆè¿™äº›çº¦å®šçš„,包括所有的 POSIX 系统,也包括个人的 Microsoft 系统。唯一对这ç§æ–¹å¼ç»“æžœä¸ç¡®å®šçš„æµ è¡Œç³»ç»Ÿæ˜¯â€œClassic†Macintosh 系统,它使用冒å·ï¼ˆcolon)而ä¸æ˜¯æ–œçº¿ã€‚ 所以 sysopen ä¸æ˜¯ä¸€ä¸ªå主æ„。

+

如果你把 <ARGV> 处ç†æˆéžé­”术的形å¼ï¼Œä½ å¯ä»¥è¿™æ ·ï¼š If you want to use <ARGV> processing in a totally boring and non-magical way, you could do this first:

+
    #   "Sam sat on the ground and put his head in his hands.  
+    #   'I wish I had never come here, and I don't want to see 
+    #   no more magic,' he said, and fell silent."
+    for (@ARGV) { 
+        s#^([^./])#./$1#;
+        $_ .= "\0";
+    } 
+    while (<>) {  
+        # now process $_
+    } 
+

这样转æ¢ä¹‹åŽï¼Œç”¨æˆ·å°±ä¸èƒ½å†ç”¨â€œ-â€æ¥è¡¨ç¤ºæ ‡å‡†è¾“入了,其它标准惯例也ä¸èƒ½ç”¨äº†ã€‚

+

用路径å打开

+

你å¯èƒ½å·²ç»æ³¨æ„到 Perl çš„ warn å’Œ die 函数能产生这样的消æ¯ï¼š

+
    Some warning at scriptname line 29, <FH> line 7.
+

这是因为你打开了一个文件å¥æŸ„ FH,并从中读å–了 7 个记录。但是怎样显示文 件å,而ä¸æ˜¯æ–‡ä»¶å¥æŸ„呢?

+

如果你ä¸æ˜¯ä½¿ç”¨ strict refs,或者暂时关闭,你åªè¦åƒè¿™æ ·åšï¼š

+
    open($path, "< $path") || die "can't open $path: $!";
+    while (<$path>) {
+        # whatever
+    } 
+

因为你是用文件的路径å作为文件å¥æŸ„,你将得到这样的警告消æ¯ï¼š

+
    Some warning at scriptname line 29, </etc/motd> line 7.
+

一个å‚æ•°çš„ open

+

还记得曾ç»è¯´è¿‡ Perl çš„ open 作用两个å‚æ•°å—?那样是ä¸è´´åˆ‡çš„。你看,它也 能åªä½¿ç”¨ä¸€ä¸ªå‚数。当且仅当这个å˜é‡æ˜¯ä¸€ä¸ªå…¨å±€å˜é‡ï¼Œè€Œä¸æ˜¯è¯æ³•å˜é‡ï¼Œä½ å¯ 以åªä¼ é€’ç»™ open 一个å‚数——文件å¥æŸ„。open 将从有相åŒåå­—çš„å…¨å±€æ ‡é‡ ä¸­èŽ·å¾—è·¯å¾„å。

+
    $FILE = "/etc/motd";
+    open FILE or die "can't open $FILE: $!";
+    while (<FILE>) {
+        # whatever
+    } 
+

为什么会这样呢?æŸäº›äººä¸ºäº†è¿Žåˆé‚£äº› hysterical porpoise。那是 Perl 刚开 始的事了,或者说是以å‰çš„事了。

+

Playing with STDIN and STDOUT

+

聪明的åšæ³•æ˜¯åœ¨ç¨‹åºç»“æŸæ—¶æ˜Žç¡®çš„关闭标准输出:

+
    END { close(STDOUT) || die "can't close stdout: $!" }
+

如果你ä¸è¿™æ ·åšï¼Œå¹¶ä¸”你的程åºç”±äºŽå‘½ä»¤è¡Œçš„é‡å®šå‘使ç£ç›˜å¡«æ»¡ï¼Œå®ƒåœ¨é”™è¯¯é€€å‡º æ—¶ä¸ä¼šå‘你报告错误。

+

你也ä¸å¿…一定è¦ç”¨ç¼ºçœçš„标准输入和标准输出。如果愿æ„çš„è¯ï¼Œä½ å¯ä»¥é‡å®šå‘它 们:

+
    open(STDIN, "< datafile")
+        || die "can't open datafile: $!";
+
+    open(STDOUT, "> output")
+        || die "can't open output: $!";
+

然åŽè¿™äº›å¯ä»¥ç›´æŽ¥è®¿é—®æˆ–者传递给å­è¿›ç¨‹ã€‚这就使程åºçœ‹ä¸ŠåŽ»åƒåœ¨å‘½ä»¤è¡Œä¸­ä½¿ç”¨ é‡å®šå‘æ¥è°ƒç”¨ä¸€æ ·ã€‚

+

把这些连接到管é“中å¯èƒ½æ›´æœ‰è¶£ã€‚例如:

+
    $pager = $ENV{PAGER} || "(less || more)";
+    open(STDOUT, "| $pager")
+        || die "can't fork a pager: $!";
+

这使得你的程åºçœ‹ä¸ŠåŽ»æ˜¯ä»¥æ ‡å‡†è¾“出通过管é“指å‘页显示程åºçš„æ–¹å¼æ¥è°ƒç”¨ã€‚ä½  也å¯ä»¥ä½¿ç”¨è¿™ä¸ªæ–¹æ³•è¿žæŽ¥åˆ°ä¸€ä¸ªéšå¼çš„ fork。如果你对你的程åºè¿›è¡ŒåŽå¤„ç†çš„ è¯ï¼Œä½ å¯ä»¥åœ¨ä¸åŒçš„进程中这样åšï¼š

+
    head(100);
+    while (<>) {
+        print;
+    } 
+
+    sub head {
+        my $lines = shift || 20;
+        return if $pid = open(STDOUT, "|-");       # return if parent
+        die "cannot fork: $!" unless defined $pid;
+        while (<STDIN>) {
+            last if --$lines < 0;
+            print;
+        } 
+        exit;
+    } 
+

这个技术å¯ä»¥åœ¨è¾“出æµä¸Šæ”¾ç½®ä»»æ„æ•°é‡çš„过滤器。

+

Other I/O Issues

+

这些内容和 open å’Œ sysopen 没有关系,但是它们影å“你对打开文件的 æ“作。

+

打å¼€éžæ–‡ä»¶çš„文件

+

什么时候一个文件ä¸æ˜¯ä¸€ä¸ªæ–‡ä»¶å‘¢ï¼Ÿä½ å¯ä»¥è¯´è¿™ä¸ªæ–‡ä»¶å­˜åœ¨ï¼Œä½†æ˜¯ä¸æ˜¯ä¸€ä¸ª plain 文件。åªæ˜¯ä»¥é˜²ä¸‡ä¸€ï¼Œæˆ‘们先è¦æ£€æŸ¥å®ƒæ˜¯ä¸æ˜¯ä¸€ä¸ªç¬¦å·é“¾æŽ¥ï¼š

+
    if (-l $file || ! -f _) {
+        print "$file is not a plain file\n";
+    } 
+

还有什么类型的文件呢?目录ã€ç¬¦å·é“¾æŽ¥ã€å‘½å管é“ã€Unix-domain 套接字〠block å’Œ character device。这些都是文件,åªä¸è¿‡ä¸æ˜¯ plain 文件。 plain 文件和文本文件是相åŒçš„概念。ä¸æ˜¯æ‰€æœ‰çš„文本文件都是 plain 文件, ä¸æ˜¯æ‰€æœ‰çš„ plain 文件都是文本文件。这也是为什么有 -f å’Œ -T 文件 测试。

+

为了打开目录,你应当用 opendir 函数,然åŽç”¨ readdir æ¥å¤„ç†ï¼Œå¦‚æžœ 有必è¦çš„è¯ï¼Œæ¢å¤ç›®å½•å:

+
    opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
+    while (defined($file = readdir(DIR))) {
+        # do something with "$dirname/$file"
+    }
+    closedir(DIR);
+

如果你è¦é€’归的处ç†ç›®å½•ï¼Œæœ€å¥½ä½¿ç”¨ File::Find 模å—。例如,这是递归地输出 所有文件,如果文件是一个目录的è¯ï¼Œè¾“出一个斜线:

+
    @ARGV = qw(.) unless @ARGV;
+    use File::Find;
+    find sub { print $File::Find::name, -d && '/', "\n" }, @ARGV;
+

这是找出在一个特定目录下所有的错误符å·é“¾æŽ¥ï¼š

+
    find sub { print "$File::Find::name\n" if -l && !-e }, $dir;
+

正如你所看到的那样,如果是一个符å·é“¾æŽ¥ï¼Œä½ å¯ä»¥æŠŠå®ƒå½“作它指å‘的文件。或 者,如果你想知é“它指å‘什么,å¯ä»¥è°ƒç”¨ readlink

+
    if (-l $file) {
+        if (defined($whither = readlink($file))) {
+            print "$file points to $whither\n";
+        } else {
+            print "$file points nowhere: $!\n";
+        } 
+    } 
+

打开命å管é“

+

命å管é“是å¦ä¸€ç§ç±»åž‹ã€‚ä½ å¯ä»¥æŠŠå®ƒå½“作普通文件,但是åªæœ‰åŒæ—¶æœ‰è¯»æ–¹ (reader)和写方(writer)存在时,它æ‰ä¸ä¼šé˜»å¡žã€‚更多内容å‚è§ "Named Pipes" in perlipc。Unix-domain 套接字也相当ä¸åŒï¼Œåœ¨ "Unix-Domain TCP Clients and Servers" in perlipc 中有æ述。

+

当ä½ è¦æ‰“开设备时,有容易的方法,也有çªé—¨ã€‚å‡å®šä½ è¦æ‰“开一个å—设备,你知 é“你在åšä»€ä¹ˆã€‚字符设备更有趣。它们通常用于调制解调器ã€é¼ æ ‡å’ŒæŸäº›æ‰“字机。 å‚è§ "How do I read and write the serial port?" in perlfaq8 。打开它们 æ—¶è¦ç‰¹åˆ«å°å¿ƒï¼š

+
    sysopen(TTYIN, "/dev/ttyS1", O_RDWR | O_NDELAY | O_NOCTTY)
+                # (O_NOCTTY no longer needed on POSIX systems)
+        or die "can't open /dev/ttyS1: $!";
+    open(TTYOUT, "+>&TTYIN")
+        or die "can't dup TTYIN: $!";
+
+    $ofh = select(TTYOUT); $| = 1; select($ofh);
+
+    print TTYOUT "+++at\015";
+    $answer = <TTYIN>;
+

对于还没有用 c<sysopen> 打开的æ述符,例如套接字,你å¯ä»¥ç”¨ fcntl å°† 它们设置æˆéžé˜»å¡žçš„:

+
    use Fcntl;
+    my $old_flags = fcntl($handle, F_GETFL, 0) 
+        or die "can't get flags: $!";
+    fcntl($handle, F_SETFL, $old_flags | O_NONBLOCK) 
+        or die "can't set non blocking: $!";
+

如果你打算æ“作 tty,为了é¿å…在曲折的 ioctl åŠå…¶å®ƒä¸ç›¸åŒçš„东西中迷 路,如果有 stty 程åºæœ€å¥½è°ƒç”¨è¿™ä¸ªç¨‹åºï¼Œå¦åˆ™ä½¿ç”¨ POSIX 接å£ã€‚è¦å¼„清楚这 些,你需è¦é˜…读 termios(3) 手册页,它æ述了 tty çš„ POSIX ç•Œé¢ï¼Œè¿˜æœ‰ POSIX,它æ述了 Perl çš„ POSIX 接å£ã€‚å¦å¤–还有一些高层的 CPAN 模å—能 够帮助你。å¯ä»¥è¯•è¯• Term::ReadKey å’Œ Term::ReadLine。

+

打开套接字

+

还有什么å¯ä»¥æ‰“开呢?使用套接字打开一个连接,你ä¸ä¼šä½¿ç”¨ Perl 的两个 open 函数。å‚考 "Sockets: Client/Server Communication" in perlipc。è¿™ 里有一个例å­ã€‚有了这个,你就å¯ä»¥æŠŠ FH 当作åŒå‘文件å¥æŸ„了:

+
    use IO::Socket;
+    local *FH = IO::Socket::INET->new("www.perl.com:80");
+

如æžœè¦æ‰“开一个 URL,CPAN çš„ LWP 模å—是首选。它没有文件å¥æŸ„接å£ï¼Œä½†æ˜¯ä» 然å¯ä»¥å¾ˆæ–¹ä¾¿çš„得到文档的内容:

+
    use LWP::Simple;
+    $doc = get('http://www.linpro.no/lwp/');
+

二进制文件

+

在一些å¤è‘£çº§çš„系统中,它们有,说得好å¬çš„,被称为æžç«¯è´¹è§£çš„(有些人会说是å 掉的)I/O 模型。一个文件ä¸æ˜¯ä¸€ä¸ªæ–‡ä»¶â€”—至少ä¸ç¬¦åˆ C 标准 I/O 库。在这些 è€å¼ç³»ç»Ÿä¸­ï¼Œåº“(但ä¸æ˜¯å†…核)会区分文本和二进制æµã€‚为了使文件显得正常, 你花很大力气去é¿å…讨厌的问题。在这些倒霉的系统中,套接字和管é“å·²ç»ç”¨äºŒ 进制模å¼æ‰“开,而且现在没有办法把它们关掉。但是对于文件,你还是有更多选 择。

+

另一ç§é€‰æ‹©æ˜¯åœ¨è¿›è¡Œå¸¸è§„ I/O æ“作之å‰å¯¹ç›¸åº”çš„å¥æŸ„使用 binmode 函数:

+
    binmode(STDIN);
+    binmode(STDOUT);
+    while (<STDIN>) { print } 
+

只è¦ç³»ç»Ÿæ”¯æŒï¼Œå‘ sysopen 传递éžæ ‡å‡†çš„ flag 选项也å¯ä»¥ç”¨äºŒè¿›åˆ¶æ¨¡å¼æ‰“ 开文件。这等效于以正常方å¼æ‰“开文件之åŽï¼Œå¯¹æ–‡ä»¶å¥æŸ„使用 binmode

+
    sysopen(BINDAT, "records.data", O_RDWR | O_BINARY)
+        || die "can't open records.data: $!";
+

现在你å¯ä»¥å¯¹æ–‡ä»¶å¥æŸ„用 read å’Œ print,而ä¸ç”¨æ‹…心在éžæ ‡å‡†ç³»ç»Ÿä¸­ I/O 库破åä½ çš„æ•°æ®ã€‚这虽然ä¸æ¼‚亮,但是在è€å¼ç³»ç»Ÿä¸Šå¾ˆå°‘是漂亮的。CP/M 将与我们åŒåœ¨ï¼Œç›´åˆ°ä¸–界末日,并将延续下去。

+

在一些有特殊的 I/O 体系的系统,你将惊奇的å‘现,å³ä½¿æ˜¯ä½¿ç”¨ sysread å’Œ syswrite 进行ä¸ç¼“冲的 I/O 也å¯èƒ½èƒŒç€ä½ å·å·çš„ç ´åæ•°æ®ï¼š

+
    while (sysread(WHENCE, $buf, 1024)) {
+        syswrite(WHITHER, $buf, length($buf));
+    } 
+

取决于你使用的系统,å³ä½¿æ˜¯è¿™äº›è°ƒç”¨ä¹Ÿéœ€è¦å…ˆè¿›è¡Œ binmode 或者 O_BINARY。已知的没有这些问题的系统包括 Unixã€Mac OSã€Plan 9 å’Œ Inferno。

+

文件é”定

+

在多任务环境中,你è¦å°å¿ƒä¸è¦å’Œå…¶å®ƒå¯¹ä½ å½“å‰å·¥ä½œæ–‡ä»¶è¿›è¡Œ I/O æ“作的进程 å‘生冲çªã€‚你需è¦åœ¨è¯»å†™æ–‡ä»¶æ—¶åˆ†åˆ«å¯¹æ–‡ä»¶è®¾ç½®å…±äº«æˆ–者排他é”定。你å¯ä»¥è®¤ä¸º åªæœ‰æŽ’ä»–é”定。

+

永è¿œä¸è¦ç”¨æ–‡ä»¶çš„存在 -e $file 作为é”定文件的指示,在测试文件存在和 创建文件过程之间存在竞æ€æ¡ä»¶ï¼ˆrace condition)。很å¯èƒ½åœ¨ä½ æµ‹è¯•æ–‡ä»¶å­˜åœ¨ 和试图创建文件的一瞬间å¦ä¸€ä¸ªè¿›ç¨‹åˆ›å»ºäº†è¿™ä¸ªæ–‡ä»¶ã€‚原å­æ“作是关键的。 Atomicity is critical.

+

Perl 最容易移æ¤çš„é”定接å£æ˜¯é€šè¿‡ flock 函数。在 SysV 或者 Windows è¿™ 些ä¸ç›´æŽ¥æ”¯æŒçš„系统 Perl æ供了模拟。这æ„味ç€ä¼šå½±å“它的工作方å¼ï¼Œæ‰€ä»¥ä½  应当了解 Perl 是怎样在你的系统中实现 flock 的。 The underlying semantics may affect how it all works, so you should learn how flock is implemented on your system's port of Perl.

+

文件é”定不会阻止其它进程对文件的 I/O æ“作。文件的é”定åªæ˜¯é˜»æ­¢å…¶å®ƒè¿› 程对文件加é”,而ä¸æ˜¯è¿›è¡Œ I/O æ“作。因为é”定是建议性的,如果一个进程使 用é”定,而å¦ä¸€ä¸ªä¸ç”¨ï¼Œè§„定就被打破了(all bets are off)。

+

默认情况下,在å…许é”å®šä¹‹å‰ flock 调用将被阻塞。如果没有排他的é”å®šè¦ æ±‚å…±äº«é”定是将被å…许的。如果没有任何类型的é”定,è¦æ±‚排他é”定是将被å…许 的。é”定是对文件æ述符,而ä¸æ˜¯æ–‡ä»¶å。你åªæœ‰æ‰“开一个文件åŽæ‰èƒ½é”定文件。 一旦关闭文件之åŽï¼Œä¹Ÿå°±ä¸ç»´æŒé”定状æ€äº†ã€‚

+

这是怎样对文件进行阻塞共享é”定,一般用于文件的读å–:

+
    use 5.004;
+    use Fcntl qw(:DEFAULT :flock);
+    open(FH, "< filename")  or die "can't open filename: $!";
+    flock(FH, LOCK_SH)      or die "can't lock filename: $!";
+    # now read from FH
+

你å¯ä»¥ç”¨ LOCK_NB 进行éžé˜»å¡žçš„é”定:

+
    flock(FH, LOCK_SH | LOCK_NB)
+        or die "can't lock filename: $!";
+

在进行é”定之å‰ï¼Œå…ˆé€šè¿‡è­¦å‘Šæ¥æ高用户å‹å¥½æ€§ï¼š This can be useful for producing more user-friendly behaviour by warning if you're going to be blocking:

+
    use 5.004;
+    use Fcntl qw(:DEFAULT :flock);
+    open(FH, "< filename")  or die "can't open filename: $!";
+    unless (flock(FH, LOCK_SH | LOCK_NB)) {
+        $| = 1;
+        print "Waiting for lock...";
+        flock(FH, LOCK_SH)  or die "can't lock filename: $!";
+        print "got it.\n"
+    } 
+    # now read from FH
+

在进行排他é”定时,一般用于文件写入,你è¦å°å¿ƒã€‚我们用 sysopen 打开文 件,这样在清空之å‰è¿›è¡Œé”定。你å¯ä»¥ç”¨ LOCK_EX | LOCK_NB 进行éžé˜»å¡žçš„ é”定。

+
    use 5.004;
+    use Fcntl qw(:DEFAULT :flock);
+    sysopen(FH, "filename", O_WRONLY | O_CREAT)
+        or die "can't open filename: $!";
+    flock(FH, LOCK_EX)
+        or die "can't lock filename: $!";
+    truncate(FH, 0)
+        or die "can't truncate filename: $!";
+    # now write to FH
+

最åŽï¼Œç”±äºŽä¸èƒ½é˜»æ­¢å¯¹æ— ç”¨ç©ºè®¾å¤‡å¾ªçŽ¯è°ƒç”¨ä¸­å¢žåŠ è®¡æ•°ï¼Œè¿™æ˜¯æ€Žæ ·å®‰å…¨çš„递增一 个文件中的数字。 Finally, due to the uncounted millions who cannot be dissuaded from wasting cycles on useless vanity devices called hit counters, here's how to increment a number in a file safely:

+
    use Fcntl qw(:DEFAULT :flock);
+
+    sysopen(FH, "numfile", O_RDWR | O_CREAT)
+        or die "can't open numfile: $!";
+    # autoflush FH
+    $ofh = select(FH); $| = 1; select ($ofh);
+    flock(FH, LOCK_EX)
+        or die "can't write-lock numfile: $!";
+
+    $num = <FH> || 0;
+    seek(FH, 0, 0)
+        or die "can't rewind numfile : $!";
+    print FH $num+1, "\n"
+        or die "can't write numfile: $!";
+
+    truncate(FH, tell(FH))
+        or die "can't truncate numfile: $!";
+    close(FH)
+        or die "can't close numfile: $!";
+

IO 层

+

在 Perl 5.8.0 引入了称为“PerlIOâ€çš„æ–° I/O 框架。在 Perl 中的 I/O 使用了 新的“管é“(plumbing)â€ã€‚对于大多数情况ä»ç„¶èƒ½å¤Ÿç”¨ä»¥å‰çš„æ–¹å¼å·¥ä½œï¼ŒPerlIO 也引入了一些新的特性,比如从“层â€çš„观点æ¥çœ‹ I/O。一个 I/O 层å¯èƒ½ä¸ä»…ä»… 是移动数æ®ï¼Œè¿˜è¿›è¡Œæ•°æ®çš„转æ¢ã€‚è¿™ç§è½¬æ¢åŒ…括压缩和解压缩,加密和解密,在 ä¸åŒå­—符编ç ä¹‹é—´è½¬æ¢ã€‚

+

对于 PerlIO 的特性进行详尽讨论超出本指å—的范围,这里是怎样应用 PerlIO 层的例å­ï¼š

+
    +
  • + 可以使用三个(或者更多)å‚æ•°å½¢å¼çš„ open,其中第二个å‚数除了常用的 '<''>''>>''|' åŠå…¶å˜ä½“加入其它东 西,例如: +
        open(my $fh, "<:utf8", $fn);
    +
  • +
  • + 可以使用两个å‚æ•°å½¢å¼çš„ binmode,例如: +
        binmode($fh, ":encoding(utf16)");
    +
  • +
+

对于 PerlIO 的更详细讨论请å‚考 PerlIO; 对于 Unicode å’Œ I/O 的更详细讨论请å‚考 perluniintro

+

SEE ALSO

+

perlfunc(1) 中的 open 和 sysopen 函数;manpage 中系统 open(2),dup(2),fopen(3) 和 fdopen(3);POSIX 文档。

+

AUTHOR and COPYRIGHT

+

Copyright 1998 Tom Christiansen.

+

This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.

+

Irrespective of its distribution, all code examples in these files are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required.

+

HISTORY

+

第一次å‘布: Sat Jan 9 08:09:11 MST 1999

+

TRANSLATORS

+

YE Wenbin redcandle(redcandle51@chinaren.com)

+ + diff --git a/POD/CN_html/perlreftut.html b/POD/CN_html/perlreftut.html new file mode 100644 index 0000000..1aa22e1 --- /dev/null +++ b/POD/CN_html/perlreftut.html @@ -0,0 +1,222 @@ + + + + perlreftut + + + + +

NAME

+

perlreftut - Mark 的关于引用的简短指å—

+

DESCRIPTION

+

Perl5 最é‡è¦çš„新特性之一就是å¯ä»¥ç®¡ç†å¤æ‚æ•°æ®ç»“构比如多维数组或者嵌套的哈 希。为了实现这一功能,Perl5 引进了一个新的特性称为“引用â€ï¼Œå¼•ç”¨æ˜¯ç®¡ç† Perl 中å¤æ‚æ•°æ®ç»“构的关键。ä¸å¹¸çš„是,这其中有大é‡æœ‰æ„æ€çš„语法需è¦å­¦ä¹ ï¼Œ 主体手册掌æ¡èµ·æ¥æœ‰ä¸€å®šå›°éš¾ã€‚虽然它相当完整,但是有时候也存在问题,它很难 讲明哪些是é‡è¦çš„,哪些ä¸æ˜¯ã€‚

+

幸è¿çš„是,你åªéœ€è¦äº†è§£ä¸»ä½“手册的 10% å°±å¯ä»¥å¾—到 90% 的好处。本指å—å°±å°†å‘ ä½ å±•ç¤ºè¿™ 10%。

+

谁需è¦å¤æ‚æ•°æ®ç»“æž„

+

一ç›´ä»¥æ¥ Perl4 中都存在ç€å¦‚何表示一个包å«çš„列表值的哈希结构的问题。Perl4 当然也有哈希,但是它的值åªèƒ½æ˜¯æ ‡é‡ï¼Œè€Œä¸èƒ½æ˜¯åˆ—表。

+

为什么需è¦ä¸€ä¸ªåŒ…å«åˆ—表的哈希呢?我们举一个简å•çš„例å­ï¼šä½ æœ‰ä¸€ä¸ªåŒ…å«åŸŽå¸‚å’Œ 国家å称的文件,如:

+
        Chicago, USA
+        Frankfurt, Germany
+        Berlin, Germany
+        Washington, USA
+        Helsinki, Finland
+        New York, USA
+

你想产生这样一个输出,æ¯ä¸ªå›½å®¶ä»…被æ到一次,åŽé¢è·Ÿç€æŒ‰å­—æ¯æŽ’åºçš„该国城市 çš„å称

+
        Finland: Helsinki.
+        Germany: Berlin, Frankfurt.
+        USA:  Chicago, New York, Washington.
+

很自然的方法就是用一个键值为国家å称的哈希æ¥è¡¨ç¤ºã€‚与æ¯ä¸ªå›½å®¶å称相关è”çš„ 是这个国家的城市列表。æ¯æ¬¡ä½ è¯»å…¥ä¸€è¡Œè¾“入,就将它分割æˆä¸€ä¸ªå›½å®¶å称和城市 å称,在该国家已有的城市列表中查找å称或往列表中加入新的城市。当你读完输 入之åŽï¼ŒæŒ‰ç…§å¹³å¸¸çš„æ–¹å¼è¿­ä»£é历整个哈希,并将æ¯ä¸ªåˆ—表中的城市排åºåŽè¾“出。

+

如果哈希的å–值ä¸èƒ½æ˜¯åˆ—表,你就没法实现了。在 Perl4 中,哈希的值ä¸èƒ½æ˜¯åˆ— 表,åªèƒ½ç”¨å­—符串表示。你也许åªèƒ½è®¾æ³•å°†æ‰€æœ‰åŸŽå¸‚组åˆæˆä¸€ä¸ªç®€å•çš„字符串,然 åŽåœ¨è¾“出的时候将字符串分割æˆåˆ—表,将列表排åºï¼Œå†è½¬æ¢å›žå­—符串。这ç§æ–¹æ³•å‡Œ 乱而易出错,并且也很挫伤人,因为 Perl 本身有完美的列表å¯ä»¥è§£å†³è¿™ä¸ªé—®é¢˜ï¼Œ åªè¦ä½ å¯ä»¥ä½¿ç”¨å®ƒã€‚

+

解决方案在哪里?

+

在 Perl5 开始普åŠæ—¶ï¼Œæˆ‘们已ç»ä¹ æƒ¯äºŽè¿™æ ·çš„设计:哈希的值必须是标é‡ã€‚这就 需è¦ä½¿ç”¨å¼•ç”¨æ¥è§£å†³è¿™ä¸ªé—®é¢˜ã€‚

+

引用是一个指å‘整个数组或整个哈希(或者其他任何东西)的标é‡ã€‚姓å是你已 ç»éžå¸¸ç†Ÿæ‚‰çš„引用之一。考虑一下美国总统:一副乱七八糟的皮肉。但是谈到他或 者在程åºä¸­è¡¨ç¤ºä»–,你åªéœ€è¦ä¸€ä¸ªç®€å•çš„æ ‡é‡å­—符串“乔治·布什â€ã€‚

+

Perl 中的引用就åƒæ•°ç»„和哈希的å字。他们是 Perl çš„ç§æœ‰å’Œå†…部å字,所以你 å¯ä»¥ä¿è¯ä»–们ä¸ä¼šæ··æ·†ã€‚和“乔治·布什â€ä¸åŒçš„是,很多人都å¯ä»¥å«è¿™ä¸ªå字, 但是一个引用å´åªæŒ‡å‘一个事物,并且你总是了解它指å‘什么。如果你拥有一个数 组的引用,那么你å¯ä»¥ä»Žä¸­å–得整个数组。如果你有一个哈希的引用,那么你也能 æ¢å¤æ•´ä¸ªå“ˆå¸Œã€‚但是引用ä»ç„¶æ˜¯ä¸€ä¸ªç®€å•ã€ç´§å‡‘çš„æ ‡é‡å€¼ã€‚

+

你ä¸èƒ½å¾—到一个包å«æ•°ç»„值的哈希;哈希值åªèƒ½æ˜¯æ ‡é‡ã€‚我们åšæŒè¿™ä¸ªåŽŸåˆ™ã€‚但是 一个引用å¯ä»¥è¡¨ç¤ºæ•´ä¸ªæ•°ç»„,并且引用是标é‡ï¼Œæ‰€ä»¥ä½ å¯ä»¥æ‹¥æœ‰ä¸€ä¸ªåŒ…å«å“ˆå¸Œå¼•ç”¨ 的数组,它看起æ¥å°±åƒæ˜¯æ•°ç»„的哈希并且和数组的哈希一样有用。

+

我们待会儿å†è®¨è®ºåŸŽå¸‚-国家问题,在我们看一下管ç†å¼•ç”¨çš„语法之åŽã€‚

+

语法

+

有两ç§åˆ›å»ºå¼•ç”¨çš„方法,也åªæœ‰ä¸¤ç§æ–¹æ³•å¯ä»¥ä½¿ç”¨å®ƒã€‚

+

创建引用

+

创建规则一

+

如果你在å˜é‡å‰é¢åŠ ä¸€ä¸ª \,那么你就得到了它的引用。

+
    $aref = \@array;         # $aref ä¿å­˜ @array 的引用
+    $href = \%hash;          # $href ä¿å­˜ %hash 的引用
+

一æ—¦å¼•ç”¨è¢«å‚¨å­˜åœ¨ä¸€ä¸ªåƒ $aref 或 $href çš„å˜é‡ä¸­ï¼Œä½ å°±å¯ä»¥åƒå…¶ä»–æ ‡é‡å€¼ä¸€æ · 对它进行拷è´æˆ–储存。

+
    $xy = $aref;             # $xy ä¿å­˜ @array的引用
+    $p[3] = $href;           # $p[3] ä¿å­˜ %hash的引用
+    $z = $p[3];              # $z ä¿å­˜ %hash的引用
+

这些例å­æ˜¾ç¤ºäº†å¦‚何从å字中创建引用。有时候你想è¦åˆ›å»ºä¸€ä¸ªæ²¡æœ‰å字的数组或 哈希的引用,这个就åƒä½ å¯ä»¥ä½¿ç”¨ \n 这个字符串或者 80 这样的直接é‡, 而你并没有将他们存储在任何å˜é‡ä¸­ä¸€æ ·ã€‚

+

创建规则二

+

[ ITEMS ] 创建一个新的,匿å数组,并且返回该数组的引用。{ ITEMS } 创建一个新的匿å哈希,并返回这个哈希的引用。

+
    $aref = [ 1, "foo", undef, 13 ];  
+    # $aref ä¿å­˜ä¸€ä¸ªæ•°ç»„的引用
+
+    $href = { APR => 4, AUG => 8 };   
+    # $href ä¿å­˜ä¸€ä¸ªå“ˆå¸Œçš„引用
+

通过规则一创建的引用与通过规则二创建的引用效果完全相åŒï¼š

+
        # 下é¢è¿™å¥
+        $aref = [ 1, 2, 3 ];
+
+        # 其实就相当于
+        @array = (1, 2, 3);
+        $aref = \@array;
+

第一行是下é¢ä¸¤è¡Œçš„缩写,åªä¸è¿‡å®ƒä¸åˆ›å»ºå¤šä½™çš„数组å˜é‡ @array

+

如果你输入åªè¾“å…¥ [],你就会得到一个新的空的匿å数组。 如果你åªè¾“å…¥ {},你就会得到一个新的空的匿å哈希。

+

使用引用

+

在得到引用之åŽä½ è¯¥å¦‚何使用它呢?这是一个标é‡ï¼Œæˆ‘们已ç»çœ‹åˆ°å¯ä»¥å°†å®ƒå½“作标 é‡å­˜å‚¨èµ·æ¥å¹¶åƒä¸€ä¸ªæ ‡é‡ä¸€æ ·é‡æ–°å–得它。此外还有两ç§ä½¿ç”¨å®ƒçš„方法。

+

用法规则一

+

你总是å¯ä»¥ç”¨èŠ±æ‹¬å·æ‹¬èµ·çš„数组引用æ¥ä»£æ›¿æ•°ç»„å称。例如,@{$aref} å¯ä»¥ç”¨ æ¥ä»£æ›¿ @array

+

这里有一些例å­

+

数组:

+
        @a              @{$aref}                一个数组
+        reverse @a      reverse @{$aref}        将数组翻转
+        $a[3]           ${$aref}[3]             数组的一个元素
+        $a[3] = 17;     ${$aref}[3] = 17        给一个元素赋值
+

每一行中的表达å¼éƒ½åšåŒæ ·çš„事情。左边的版本æ“作数组 @a。å³è¾¹çš„版本æ“作 $aref 指å‘的数组。对于åŒä¸€ä¸ªæ•°ç»„æ¥è¯´ï¼Œä¸¤ç§æ–¹å¼çš„效果是一样的。

+

使用哈希的引用也完å…¨一样:

+
        %h              %{$href}              一个哈希
+        keys %h         keys %{$href}         获å–哈希的键值列表
+        $h{'red'}       ${$href}{'red'}       访问哈希的一个元素
+        $h{'red'} = 17  ${$href}{'red'} = 17  给哈希的元素赋值
+

不论你想è¦ç”¨å¼•ç”¨æ¥åšä»€ä¹ˆï¼Œä½¿ç”¨ç”¨æ³•è§„则一都å¯ä»¥åšåˆ°ã€‚ä½ åªéœ€è¦è±¡å¾€å¸¸ä¸€æ ·ä½¿ 普通的数组或者哈希æ¥å†™ç¨‹åºï¼Œç„¶åŽå†æŠŠæ•°ç»„或者哈希的åå­—æ¢æˆ $reference 就行了。“我如何通过一个引用æ¥é历一个数组?â€ï¼Œå¾ˆç®€å•ï¼Œå¦‚果你想é历一个 数组,那你得这么写:

+
        for my $element (@array) {
+           ...
+        }
+

然åŽï¼ŒæŠŠæ•°ç»„å array æ¢æˆå¼•ç”¨å°±å¯ä»¥äº†ï¼š

+
        for my $element (@{$aref}) {
+           ...
+        }
+

“我怎么样通过引用æ¥æ‰“å°å‡ºå“ˆå¸Œçš„内容?â€ï¼Œä½ å¯ä»¥å…ˆå†™ä¸€ä¸ªæ‰“å°å“ˆå¸Œçš„程åºï¼š

+
        for my $key (keys %hash) {
+          print "$key => $hash{$key}\n";
+        }
+

然åŽæŠŠå“ˆå¸Œçš„åå­—æ¢æˆå¼•ç”¨å°±å¯ä»¥äº†ï¼š

+
        for my $key (keys %{$href}) {
+          print "$key => ${$href}{$key}\n";
+        }
+

用法规则二

+

有了用法规则一在大多数时候就已ç»å¤Ÿç”¨äº†ï¼Œå› ä¸ºå®ƒå‘Šè¯‰äº†ä½ ä¸€ä¸ªä»¥ä¸å˜åº”ä¸‡å˜ çš„å¼•ç”¨ç”¨æ³•ã€‚ä½†æ˜¯å¤§å¤šæ•°æ—¶å€™æˆ‘ä»¬åªéœ€è¦è®¿é—®æ•°ç»„或者哈希的一个元素,这时候用 法规则一就显得太ç¹ç了。所以下é¢ä»‹ç»ä¸€ç§ç®€å†™æ–¹å¼ï¼š

+

考虑一下如何通过一个引用去访问数组的第 4 个元素?得这样:${$aref}[3],å¯ æ˜¯è¿™ç§å†™æ³•å¾ˆéš¾è¯»æ‡‚,那你å¯ä»¥å†™æˆ $aref->[3] æ¥ä»£æ›¿ã€‚

+

${$href}{red} 也很难懂,那我们å¯ä»¥ç”¨ $href->{red} 代替。

+

如æžœ $aref ä¿å­˜äº†ä¸€ä¸ªæŒ‡å‘数组的引用,那么 $aref->[3] çš„æ„æ€å°±æ˜¯ å–这个数组的第 4 个元素。åƒä¸‡ä¸å¥½å’Œ $aref[3] 混淆,åŽè€…表示的是 @aref è¿™ 个数组的第四个元素 ^_^。$ref å’Œ @aref 完全无关。

+

同样地,$href->{'red'} 表示哈希引用 $href 的一个元素。åŒæ ·åœ°ï¼Œä½  ä¸èƒ½æŠŠå®ƒå’Œ $href{'red'} 混淆,因为åŽè€…访问的是 %href 这个哈希的内容。忘记 书写 -> 将导致你的程åºå‡ºçŽ°ä¸€äº›èŽ«å其妙的问题。因为你访问的数组和哈 希其实都ä¸æ˜¯ä½ æƒ³è¦è®¿é—®çš„。

+

一个例å­

+

让我们æ¥çœ‹ä¸€ä¸ªç®€çŸ­çš„例å­ã€‚

+

首å…ˆï¼Œè®°ä½ [1, 2, 3] 将创建一个包å«æœ‰ (1, 2, 3) 三个数字的匿å数组, 并且返回指å‘这个匿å数组的引用。

+

现在看看这个:

+
        @a = ( [1, 2, 3],
+               [4, 5, 6],
+               [7, 8, 9]
+             );
+

@a 是一个包å«æœ‰ä¸‰ä¸ªå…ƒç´ çš„数组,它的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯æŒ‡å‘别的数组的引用。

+

$a[1] 是这些引用其中的一个,它指å‘ä¸€ä¸ªæ•°ç»„ï¼Œè¿™ä¸ªæ•°ç»„åŒ…å« (4, 5, 6), 并且,因为它是一个数组的引用,所以根æ®用法规则二,我们å¯ä»¥ç”¨ $a[1]->[2] æ¥èŽ·å–这个数组的第三个元素。所以 $a[1]->[2] 就是 6。

+

同样地,$a[0]->[1] 就是 2,这就好åƒæˆ‘们有了一个二维数组一样,你å¯ä»¥ 通过 $a[è¡Œ]->[列] æ¥èŽ·å–或者设置任æ„行任æ„列的元素的值。

+

这看起æ¥ä»ç„¶æœ‰äº›ç¹ç,所以下é¢å†ä»‹ç»ä¸€ç§æ›´åŠ ç®€ä¾¿çš„写法:

+

箭头规则

+

在两个下标之间,箭头å¯ä»¥çœç•¥ã€‚

+

于是,$a[1]->[2] å°±å¯ä»¥å†™ä½œ $a[1][2],它们是åŒä¸€ä¸ªæ„æ€ã€‚ $a[0]->[1] = 23, å°±å¯ä»¥å†™ä½œ $a[0][1] = 23,它们也是åŒä¸€ä¸ªæ„æ€ã€‚

+

现在看上去真的和二维数组很åƒäº†ï¼

+

箭头和çœç•¥ç®­å¤´è¿™ä¸¤ä¸ªè§„则éžå¸¸é‡è¦ã€‚如果没有了它们,我们就必须把 $a[1][2] 写æˆæ˜¯ ${$a[1]}[2]。三维数组 $x[2][3][5] 就必须写æˆæ˜¯ ${${$x[2]}[3]}[5],哦,那简直是一场æ¶æ¢¦ã€‚

+

解决方案

+

现在就å¯ä»¥å›žç­”开始æ出的问题了。下é¢çš„程åºå°±å¯ä»¥å¯¹å›½å®¶Â·åŸŽå¸‚åé‡æ–°æ•´ç†ï¼š

+
    1   my %table;
+
+    2   while (<>) {
+    3    chomp;
+    4     my ($city, $country) = split /, /;
+    5     $table{$country} = [] unless exists $table{$country};
+    6     push @{$table{$country}}, $city;
+    7   }
+
+    8   foreach $country (sort keys %table) {
+    9     print "$country: ";
+   10     my @cities = @{$table{$country}};
+   11     print join ', ', sort @cities;
+   12     print ".\n";
+   13   }
+

这个程åºåˆ†ä¸¤éƒ¨åˆ†ï¼šç¬¬ 2-7 行读入输入数æ®å¹¶ä¸”创建一个数æ®ç»“构,然åŽç¬¬ 8-13 行分æžè¿™äº›æ•°æ®å¹¶äº§ç”ŸæŠ¥è¡¨ã€‚我们设计了一张哈希表,%table,它的æ¯ä¸ªé”®æ˜¯ 一个国家å,对应的值则是一个指å‘数组的引用,数组中存放城市å。整个数æ®ç»“ 构看起æ¥å°±åƒæ˜¯è¿™æ ·ï¼š

+
           %table
+        +-------+---+   
+        |       |   |   +-----------+--------+
+        |Germany| *---->| Frankfurt | Berlin |
+        |       |   |   +-----------+--------+
+        +-------+---+
+        |       |   |   +----------+
+        |Finland| *---->| Helsinki |
+        |       |   |   +----------+
+        +-------+---+
+        |       |   |   +---------+------------+----------+
+        |  USA  | *---->| Chicago | Washington | New York |
+        |       |   |   +---------+------------+----------+
+        +-------+---+
+

我们先看看输出部分。å‡å¦‚我们已ç»æ‹¥æœ‰äº†è¿™æ ·çš„一个数æ®ç»“构,那么我们该怎样 打å°å®ƒå‘¢ï¼Ÿ

+
    8   foreach $country (sort keys %table) {
+    9     print "$country: ";
+   10     my @cities = @{$table{$country}};
+   11     print join ', ', sort @cities;
+   12     print ".\n";
+   13   }
+

%table 是一个普通的哈希表,我们å–出它所有的键,并且进行排åºï¼Œç„¶åŽé历 这些键,这些和往常没有什么ä¸åŒã€‚这里仅仅åªåœ¨ç¬¬ 10 行使用了引用。 $table{$country} 从哈希表中检索 $country 对应的值,这个值就是一个指 å‘这个国家城市列表的一个引用。根æ®用法规则一,我们å¯ä»¥ç”¨ @{$table{$country}} 还原这个数组。所以第 10 行就好åƒæ˜¯ï¼š

+
        @cities = @array;
+

唯一ä¸åŒçš„地方是数组å array 被 $table{$country} 代替了。@ 告诉 Perl 得到整个数组。然åŽæˆ‘们对这个数组用 sort 排åºã€ç”¨ join 连接,最åŽæ‰“å°å®ƒã€‚

+

第 2-7 行负责构造数æ®ç»“构。我们å†æ¥çœ‹çœ‹ï¼š

+
    2   while (<>) {
+    3    chomp;
+    4     my ($city, $country) = split /, /;
+    5     $table{$country} = [] unless exists $table{$country};
+    6     push @{$table{$country}}, $city;
+    7   }
+

第 2-4 行得到城市å和国家å,第 5 行检查国家å对应的键值是å¦å·²ç»åœ¨å“ˆå¸Œè¡¨ 中存在。如果ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆå°±ç”¨ [] 创建一个新的空匿å数组,并且把引用挂到 哈希表中国家å对应的æ¡ç›®ä¸­ã€‚

+

第 6 行把城市å加入到适当的数组中去。现在 $table{$country} 指å‘一个城市 å数组,所以第 6 行看上去就åƒæ˜¯ï¼š

+
        push @array, $city;
+

唯一ä¸åŒçš„地方就是数组å array 被 {$table{$country}} 代替了。push è¿ç®—符把城市å添加到引用指å‘的数组的末尾。

+

其实第 5 行完全是ä¸å¿…è¦çš„。也就是说,也å¯ä»¥å†™æˆè¿™æ ·ï¼š

+
    2   while (<>) {
+    3    chomp;
+    4     my ($city, $country) = split /, /;
+    5   ####  $table{$country} = [] unless exists $table{$country};
+    6     push @{$table{$country}}, $city;
+    7   }
+

如国 %table 中已ç»å­˜åœ¨äº† $country 对应的æ¡ç›®ï¼Œé‚£ä¹ˆæœ‰æ²¡æœ‰ç¬¬ 5 行并没 有什么分别。第 6 行将定ä½åˆ° $table{$country} 并且把 $city push 进去。 但是如果哈希表中并没有 $country 这样一个键,那么会å‘生什么事呢?

+

Perl 对这时应该å‘生的行为åšäº†æ˜Žç¡®çš„å®šä¹‰ã€‚å¦‚æžœä½ æƒ³è¦ push Athens 到一个 数组,而那个数组并ä¸å­˜åœ¨ï¼Œé‚£ä¹ˆ Perl 会å‹å¥½åœ°å¸®ä½ åˆ›å»ºä¸€ä¸ªæ–°çš„ã€ç©ºçš„ã€åŒ¿å 数组给你,并且把它挂在 %table 上,然åŽå†æŠŠ Athens push 进去。这å«åš `autovivification'--bringing things to life automatically.(flw æ³¨ï¼šè¿™å¥ å®žåœ¨ä¸çŸ¥è¯¥å¦‚何翻译)。Perl 看è§é‚£ä¸ªé”®ä¸åœ¨å“ˆå¸Œä¸­ï¼ŒäºŽæ˜¯å°±è‡ªåŠ¨åˆ›å»ºä¸€ä¸ªæ–°çš„ 哈希æ¡ç›®ï¼›Perl 看è§ä½ æƒ³è¦æŠŠè¿™ä¸ªæ¡ç›®ä½œä¸ºä¸€ä¸ªæ•°ç»„使用,于是它åˆè‡ªåŠ¨åœ°åˆ›å»º 一个新的空数组并且自动把引用存储到哈希中。 And as usual, Perl made the array one element longer to hold the new city name.

+

临了

+

我曾ç»ç­”应过用 10% 的内容给你 90% 的好处,这æ„味ç€ï¼Œè¿˜æœ‰ 90% 的内容我没 讲 ^_^。ä¸è¿‡çŽ°åœ¨ä½ å·²ç»å¯¹ä¸»è¦çš„东西有了一个大概的å°è±¡ï¼Œå› æ­¤ä½ å¯ä»¥å¾ˆå®¹æ˜“地 看懂 perlref,æ¥å“å° 100% 的内容。

+

阅读 perlref 时应该注æ„以下几点:

+
    +
  • 你å¯ä»¥ç»™ä»»ä½•ä¸œè¥¿åˆ›å»ºå¼•ç”¨ï¼Œä¾‹å¦‚æ ‡é‡ã€å‡½æ•°ã€ç”šè‡³æ˜¯åˆ«çš„引用。
  • +
  • 用法规则一中,如果花括å·ä¸­åªæœ‰ä¸€ä¸ªç®€å•çš„引用的è¯ï¼Œé‚£ä¹ˆèŠ±æ‹¬å·å°±å¯ä»¥ çœç•¥ã€‚例如,@$aref 就相当于 @{$aref}$$aref[1] 就相当于 ${$aref}[1]。 If you're just starting out, you may want to adopt the habit of always including the curly brackets.
  • +
  • + 还有一点,这样并ä¸èƒ½å¤åˆ¶å®ƒä»¬æŒ‡å‘的数组: +
            $aref2 = $aref1;        
    +

    这æ ·ä½ åªèƒ½å¾—到两个指å‘相åŒçš„数组的引用。如果你修改了 $aref1->[23] 那么 $aref2->[23] 会åšåŒæ ·çš„改å˜ã€‚

    +

    要想完全å¤åˆ¶æ•°ç»„,你得这样:

    +
            $aref2 = [@{$aref1}];
    +

    符å· [...] 创建一个新的匿å数组,并且把引用赋值给 $aref2,这个新 数组已ç»ç”¨ $aref1 的内容åˆå§‹åŒ–过了。

    +

    同样地,è¦æƒ³å¤åˆ¶åŒ¿å哈希,你得这样:

    +
            $href2 = {%{$href1}};
    +
  • +
  • 因为引用本æ¥å°±æ˜¯ä¸€ä¸ªæ ‡é‡ï¼Œå› æ­¤ä»Žè¡¨é¢ä¸Šæ˜¯æ— æ³•çŸ¥é“一个标é‡æ˜¯å¦å°±æ˜¯ä¸€ä¸ªå¼• 用,这时你å¯ä»¥ä½¿ç”¨ ref 函数。如果传递给 ref çš„å‚数是一个引用,它将返 回真值,事实上,如果是一个哈希引用,那么 ref 会返回 HASH,如果是一个 数组引用,ref 则返回 ARRAY
  • +
  • + 如果你把一个引用当作一个字符串æ¥ç”¨çš„è¯ï¼Œä½ å°†å¾—到类似于这样的一个结果: +
            ARRAY(0x80f5dec)   or    HASH(0x826afc0)
    +

    如果你曾ç»çœ‹åˆ°è¿‡è¿™æ ·çš„字符串,那么说明你以å‰æ›¾ç»æ‰“å°è¿‡ä¸€ä¸ªå¼•ç”¨ ^_^

    +

    这个特性的一个副作用就是你å¯ä»¥ä½¿ç”¨ eq è¿ç®—符æ¥æ¯”较两个引用是å¦æŒ‡å‘ åŒä¸€ä¸ªä¸œè¥¿ã€‚但是建议你ä¸è¦ç”¨ eq,而是用 ==,因为åŽé¢çš„这个更快 一些。

    +
  • +
  • 你也å¯ä»¥æŠŠä¸€ä¸ªå­—符串当作一个引用æ¥ç”¨ã€‚如果你把 "foo" 当作一个数组引 用,那么相当于是在访问 @foo。这个技术在术语里å«åš 软引用 或者 符å·å¼•ç”¨use strict 'refs' 声明å¯ä»¥å…³æŽ‰è¿™ä¸ªç‰¹æ€§ï¼Œå› ä¸ºå®ƒç»å¸¸ç»™äºº 们带æ¥å„å¼å„样的烦æ¼ã€‚
  • +
+

你å¯èƒ½æ›´å–œæ¬¢çœ‹ perllol 而ä¸æ˜¯ perlref。因为它讨论“列表的列表†以åŠå¤šç»´æ•°ç»„的技术。看完它之åŽï¼Œä½ è¿˜å¯ä»¥çœ‹ perldsc。è¿™æ˜¯ä¸€ä¸ªâ€œæ•°æ® ç»“æž„çƒ¹è°ƒæŒ‡å—》,它å¯ä»¥å‘Šè¯‰ä½ å¦‚何打å°æ•°ç»„的哈希ã€å“ˆå¸Œçš„数组等å¤æ‚çš„æ•°æ® ç»“æž„ã€‚

+

摘è¦

+

任何人都需è¦å¤æ‚çš„æ•°æ®ç»“构,Perl 中通过引用æ¥å¾—到解决。关于引用有四æ¡é‡ è¦è§„则:两æ¡å’Œåˆ›å»ºå¼•ç”¨æœ‰å…³çš„;两æ¡å’Œä½¿ç”¨å¼•ç”¨æœ‰å…³çš„。如果你了解了这些规 则,那么你就å¯ä»¥ç”¨å¼•ç”¨æ¥å¤„ç†å¤§å¤šæ•°é‡è¦çš„事情。

+

参与人åå•

+

作者: Mark Jason Dominus, Plover Systems (mjd-perl-ref+@plover.com)

+

这篇文章最早出自 The Perl Journal ( http://www.tpj.com/ ) å· 3, #2. å…许å†ç‰ˆã€‚

+

本文的原是标题是 Understand References Today(现在就了解引用)。

+

翻译

+

本文的开始部分(从开始截至到用法规则一)ç”± rogerz 翻译,其余部分由 flw (flw@cpan.org) 翻译,翻译æˆæžœé¦–次出现在 中国 Perl å会( http://www.perlchina.org) çš„å作开å‘å¹³å°ä¸Šã€‚

+

发布æ¡ä»¶

+

Copyright 1998 The Perl Journal.

+

本文是å¯ä»¥è‡ªç”±èŽ·å–ï¼› 你也å¯ä»¥åœ¨éµå®ˆåŒæ ·çš„æ¡æ¬¾çš„å‰æ下é‡æ–°å‘布或者/并且修改它。

+

本文中出现的所有例å­ä»£ç éƒ½æ˜¯å®Œå…¨å…¬å¼€å‘布的。我们许å¯å¹¶é¼“åŠ±ä½ å°†è¿™äº›ä»£ç  ç”¨åœ¨ä½ çš„ç¨‹åºä¸­ã€‚在代ç ä¸­ç”¨ä¸€ä¸ªç®€å•çš„注释æ¥è¯´æ˜Žå®ƒçš„å‚与人是礼貌的,但 并ä¸æ˜¯å¿…需的。

+

译者声明

+

PerlChina.org 本ç€â€œåœ¨å›½å†…推广 Perl†的目的,组织人员翻译本文。 读者å¯ä»¥åœ¨éµå®ˆåŽŸä½œè€…许å¯åè®®ã€å°Šé‡åŽŸä½œè€…åŠè¯‘作者劳动æˆæžœçš„å‰æä¸‹ï¼Œä»»æ„ å‘布或修改本文。

+

如果你对本文有任何æ„è§ï¼Œæ¬¢è¿Žæ¥ä¿¡æŒ‡æ•™ã€‚译作者欢迎此类行为但并ä¸ä¸ºæ­¤è´Ÿè´£ã€‚

+ + diff --git a/POD/CN_html/perlstyle.html b/POD/CN_html/perlstyle.html new file mode 100644 index 0000000..914965d --- /dev/null +++ b/POD/CN_html/perlstyle.html @@ -0,0 +1,128 @@ + + + + perlstyle + + + + +

NAME

+

perlstyle - Perl 风格指å—

+

DESCRIPTION

+

每一个程åºå‘˜éƒ½åº”该注æ„自己的程åºé£Žæ ¼ã€‚当然,程åºå‘˜å¯ä»¥é€‰æ‹©è‡ªå·±å–œçˆ±çš„ 风格,然而,有一些通用的规则å¯ä»¥ä½¿ä½ çš„程åºæ›´åŠ æ˜“读ã€æ˜“懂ã€æ˜“于维护。

+

The most important thing is to run your programs under the -w flag at all times. You may turn it off explicitly for particular portions of code via the no warnings pragma or the $^W variable if you must. You should also always run under use strict or know the reason why not. The use sigtrap and even use diagnostics pragmas may also prove useful.

+

任何时候都应该用 -w 选项æ¥è¿è¡Œä½ çš„程åºï¼Œè¿™ä¸€ç‚¹éžå¸¸é‡è¦ã€‚å¿…è¦çš„时候 ä½ å¯ä»¥åœ¨ç¨‹åºä¸­é€šè¿‡ no warnings 编译指示或者 $^W å˜é‡æ¥ä¸´æ—¶å…³é—­ 它。å¦å¤–,建议你在程åºå¼€å§‹å¤„加入 use strict。最åŽï¼Œuse sigtrap å’Œ use diagnostics 编译指示也æ供了一些有用的特性,你å¯ä»¥æŸ¥çœ‹å®ƒä»¬ 的手册页去åšè¿›ä¸€æ­¥çš„了解。

+

Regarding aesthetics of code lay out, about the only thing Larry cares strongly about is that the closing curly bracket of a multi-line BLOCK should line up with the keyword that started the construct. Beyond that, he has other preferences that aren't so strong:

+

在代ç æŽ’版的美观方é¢ï¼ŒLarry Wall唯一强烈建议的是,多行代ç å—之åŽçš„å³èŠ± 括å·åº”该和起始这个å—的关键字垂直对é½ã€‚å¦å¤–,他还希望你åšåˆ°ä¸‹é¢è¿™äº›ï¼ˆå°½ 管æ€åº¦ä¸æ˜¯å¾ˆå¼ºçƒˆï¼‰ï¼š

+
    +
  • 4 列缩进
  • +
  • 如æžœå¯èƒ½çš„è¯ï¼Œå·¦èŠ±æ‹¬å·å’Œå…³é”®å­—è¦å†™åœ¨åŒä¸€è¡Œï¼Œä¸ç„¶å°±å¦èµ·ä¸€è¡Œå¹¶ä¸Žå…³é”®å­—对é½ã€‚
  • +
  • 如果一个å—有多行的è¯ï¼Œå·¦èŠ±æ‹¬å·å‰é¢åº”该留有一个空格。
  • +
  • 只有一行内容的å—应该连åŒèŠ±æ‹¬å·ä¸€èµ·å†™åœ¨åŒä¸€è¡Œå†…。
  • +
  • 分å·å‰ä¸è¦åŠ ç©ºæ ¼ã€‚
  • +
  • 在较短的å•è¡Œå—中,应该çœç•¥åˆ†å·ã€‚
  • +
  • 对于大多数è¿ç®—符æ¥è¯´ï¼Œåº”该在两边å„加一个空格。
  • +
  • 较å¤æ‚些的下标(数组下标或者 hash 下标)两边应该加上空格。
  • +
  • 功能相对独立的两个程åºæ®µè½ä¹‹é—´åº”该留有空行。
  • +
  • Uncuddled elses. else应该å¦èµ·ä¸€è¡Œã€‚
  • +
  • 函数调用时,函数å称和左圆括å·ä¹‹é—´ä¸åº”留任何空白。
  • +
  • 每个逗å·ä¹‹åŽéƒ½åº”该加一个空格。
  • +
  • 长行应该在优先级较低的è¿ç®—符å³é¢æ–­è¡Œã€‚
  • +
  • Space after last parenthesis matching on current line. 本行最åŽä¸€ä¸ªç©ºæ ¼åŽåŠ ç©ºæ ¼ã€‚
  • +
  • 所有的语å¥éƒ½åº”该按照层次垂直对é½ã€‚
  • +
  • 在ä¸å¼•èµ·æ­§ä¹‰çš„å‰æ下忽略多余的标点符å·ã€‚
  • +
+

Larry 制订这些规则时自然有他的原因,ä¸è¿‡ä»–也并ä¸è¦æ±‚所有的人都和他完全 一样。(你å¯ä»¥å› åœ°åˆ¶å®œåœ°åˆ¶è®¢å‡ºè‡ªå·±çš„风格)

+

下é¢è¿˜æœ‰ä¸€äº›æ›´å¤šçš„风格问题我们一起æ¥æŽ¢è®¨ä¸€ä¸‹ï¼š

+
    +
  • + Just because you CAN do something a particular way doesn't mean that you SHOULD do it that way. Perl is designed to give you several ways to do anything, so consider picking the most readable one. For instance +

    你“能â€åšè¿™ä»¶äº‹å¹¶ä¸è¡¨ç¤ºä½ å°±â€œè¯¥â€è¿™ä¹ˆåšã€‚Perl 对任何事情往往都æ供多ç§æ–¹æ³•ï¼Œæœ€å¥½é€‰æ‹©æœ€æ˜“读的那ç§ã€‚比如:

    +
        open(FOO,$foo) || die "Can't open $foo: $!";
    +

    is better than

    +

    就比这个è¦å¥½ï¼š

    +
        die "Can't open $foo: $!" unless open(FOO,$foo);
    +

    because the second way hides the main point of the statement in a modifier. On the other hand

    +

    因为åŽä¸€ç§æ–¹æ³•æŠŠä¸»è¦çš„部分éšè—在了åŽé¢ã€‚而这个:

    +
        print "Starting analysis\n" if $verbose;
    +

    is better than

    +

    则比这个好:

    +
        $verbose && print "Starting analysis\n";
    +

    because the main point isn't whether the user typed -v or not.

    +

    因为主è¦çš„问题并ä¸åœ¨äºŽç”¨æˆ·æ˜¯å¦è¾“入了-v

    +

    Similarly, just because an operator lets you assume default arguments doesn't mean that you have to make use of the defaults. The defaults are there for lazy systems programmers writing one-shot programs. If you want your program to be readable, consider supplying the argument.

    +

    类似的,一些æ“作符有默认值并ä¸è¡¨ç¤ºä½ ä¸€å®šè¦é‡‡ç”¨å®ƒã€‚默认设置是为了给那些懒鬼系统程åºå‘˜ç”¨æ¥å†™ä¸€æ¬¡æ€§ç¨‹åºç”¨çš„。如果你希望你的程åºæ›´åŠ æ˜“读,最好æ供明确的å‚数。

    +

    Along the same lines, just because you CAN omit parentheses in many places doesn't mean that you ought to:

    +

    同æ ·é“ç†ï¼Œæœ‰äº›åœ°æ–¹æ˜¯å¯ä»¥çœç•¥æ‹¬å·ï¼Œä½†ä½ æ²¡å¿…è¦éžçœç•¥å®ƒä»¬ä¸å¯ï¼š

    +
        return print reverse sort num values %array;
    +    return print(reverse(sort num (values(%array))));
    +

    When in doubt, parenthesize. At the very least it will let some poor schmuck bounce on the % key in vi.

    +

    如æžœå¯èƒ½å­˜åœ¨æ­§ä¹‰ï¼Œå°±ç”¨æ‹¬å·ã€‚

    +

    Even if you aren't in doubt, consider the mental welfare of the person who has to maintain the code after you, and who will probably put parentheses in the wrong place.

    +

    即使如果此处没有歧义,也考虑一下在你之åŽç»´æŠ¤è¿™æ®µä»£ç çš„人的精神å¥åº·ï¼Œä»–甚至å¯èƒ½ä¼šæŠŠæ‹¬è¡Œæ”¾é”™åœ°æ–¹ã€‚

    +
  • +
  • + Don't go through silly contortions to exit a loop at the top or the bottom, when Perl provides the last operator so you can exit in the middle. Just "outdent" it a little to make it more visible: +

    不è¦åˆ»æ„è¦åœ¨å¾ªçŽ¯çš„顶部或者底部退出,perlæä¾›last操作符让你å¯ä»¥åœ¨ä¸­é—´é€€å‡ºã€‚å¯ä»¥è®©å®ƒçªå‡ºæ¥ä¸€äº›ä»¥ä¾¿æ›´æ˜¾çœ¼ã€‚

    +
        LINE:
    +        for (;;) {
    +            statements;
    +          last LINE if $foo;
    +            next LINE if /^#/;
    +            statements;
    +        }
    +
  • +
  • Don't be afraid to use loop labels--they're there to enhance readability as well as to allow multilevel loop breaks. See the previous example.

    使用循环标记也没关系,因为它们就是用æ¥å¢žåŠ å¯è¯»æ€§ä»¥åŠè®¾è®¡å¤šå±‚循环用的。看å‰é¢è¿™ä¸ªä¾‹å­ã€‚

  • +
  • Avoid using grep() (or map()) or `backticks` in a void context, that is, when you just throw away their return values. Those functions all have return values, so use them. Otherwise use a foreach() loop or the system() function instead.

    尽é‡é¿å…在空环境下使用grep() (或者map())å’Œ``,因为使用它们是为了得到它们的返回值。而如果你ä¸ç”¨å®ƒä»¬çš„返回值,那ä¸å¦‚就用 foreach 循环或者 system() 函数好了。

  • +
  • For portability, when using features that may not be implemented on every machine, test the construct in an eval to see if it fails. If you know what version or patchlevel a particular feature was implemented, you can test $] ($PERL_VERSION in English) to see if it will be there. The Config module will also let you interrogate values determined by the Configure program when Perl was installed.

    出于å¯ç§»æ¤æ€§çš„考虑,当使用è€ç‰ˆæœ¬æ²¡æœ‰çš„新特性的时候,用 eval 测试一下是å¦ä¼šå¤±è´¥ã€‚如果你知é“是在哪个版本æ‰åŠ è¿›æ¥çš„,你å¯ä»¥ç”¨$] (在c<English>中是$PERL_VERSION) 测试看看。Config 模å—也å¯ä»¥è®©ä½ å¾—到 Perl 安装时 Config 模å—çš„å„ç§å‚数。

  • +
  • Choose mnemonic identifiers. If you can't remember what mnemonic means, you've got a problem.

    选择容易记忆的å˜é‡å。如果你自己都记ä¸ä½ä½ çš„å˜é‡å,肯定就会有问题。

  • +
  • While short identifiers like $gotit are probably ok, use underscores to separate words. It is generally easier to read $var_names_like_this than $VarNamesLikeThis, especially for non-native speakers of English. It's also a simple rule that works consistently with VAR_NAMES_LIKE_THIS.

    虽然短åå­—åƒ $gotit 这样的也还凑åˆï¼Œä½†æ˜¯æœ€å¥½è¿˜æ˜¯ç”¨ä¸‹åˆ’线分隔一下å•è¯ã€‚$var_name 总比 $VarNamesLikeThis è¦æ˜“读,特别是éžè‹±è¯­å›½å®¶çš„人。å³ä½¿å½“å˜é‡åå˜æˆ VAR_NAME_LIKE_THIS 的时候这个规则ä»ç„¶é€‚用。

    Package names are sometimes an exception to this rule. Perl informally reserves lowercase module names for "pragma" modules like integer and strict. Other modules should begin with a capital letter and use mixed case, but probably without underscores due to limitations in primitive file systems' representations of module names as files that must fit into a few sparse bytes.

    模å—å有时则会例外。Perl 一般将å°å†™å­—æ¯çš„å字留给 pragma 模å—,åƒinteger å’Œstrict。其他模å—则应该用大写字æ¯å¼€å¤´ï¼ŒåŒæ—¶ä½¿ç”¨æ··åˆå¤§å°å†™çš„风格,而且没有下划线,因为æŸäº›åŽŸå§‹çš„系统ä¸èƒ½æ”¯æŒå¾ˆé•¿çš„文件å。

  • +
  • + You may find it helpful to use letter case to indicate the scope or nature of a variable. For example: +

    有时有用字符的大å°å†™æ¥è¡¨ç¤ºå˜é‡çš„性质和作用域也是有用的,比如:

    +
        $ALL_CAPS_HERE   constants only (beware clashes with perl vars!)
    +    $Some_Caps_Here  package-wide global/static
    +    $no_caps_here    function scope my() or local() variables
    +
    +    $ALL_CAPS_HERE   常é‡ï¼ˆå°å¿ƒäºŽperl内置å˜é‡å†²çªï¼‰
    +    $Some_Caps_Here  包内é™æ€é‡/常é‡
    +    $no_capts_here   函数作用域的 my() 或者local() å˜é‡
    +

    Function and method names seem to work best as all lowercase. E.g., $obj->as_string().

    +

    You can use a leading underscore to indicate that a variable or function should not be used outside the package that defined it.

    +

    函æ•°å和方法最好使用全å°å†™ï¼Œæ¯”如:$obj->as_string()。

    +
  • +
  • If you have a really hairy regular expression, use the /x modifier and put in some whitespace to make it look a little less like line noise. Don't use slash as a delimiter when your regexp has slashes or backslashes.

    如果你有一个相当ç¹ç的正则表达å¼ï¼Œç”¨/x修饰符以åŠä¸€äº›ç©ºæ ¼è®©å®ƒä»¬æ›´å®¹æ˜“ç†è§£ä¸€äº›ã€‚当你的正则表达å¼ä¸­æœ‰æ–œçº¿æˆ–å斜线时,ä¸è¦ç”¨æ–œçº¿ä½œä¸ºåˆ†éš”符。

  • +
  • Use the new "and" and "or" operators to avoid having to parenthesize list operators so much, and to reduce the incidence of punctuation operators like && and ||. Call your subroutines as if they were functions or list operators to avoid excessive ampersands and parentheses.

    用æ–°çš„ and å’Œ or æ“作符æ¥é¿å…使用过多的括å·ä»¥åŠ&&||。åƒç”¨åˆ—æ“作符一样调用你的函数æ¥é¿å…过多的括å·ã€‚

  • +
  • Use here documents instead of repeated print() statements.

    使用本地文档代替åå¤çš„print()语å¥ã€‚

  • +
  • + Line up corresponding things vertically, especially if it'd be too long to fit on one line anyway. +

    垂直对é½ç›¸åº”的部分,尤其是当一行写ä¸ä¸‹çš„时候。

    +
        $IDX = $ST_MTIME;
    +    $IDX = $ST_ATIME       if $opt_u;
    +    $IDX = $ST_CTIME       if $opt_c;
    +    $IDX = $ST_SIZE        if $opt_s;
    +
    +    mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!";
    +    chdir($tmpdir)      or die "can't chdir $tmpdir: $!";
    +    mkdir 'tmp',   0777 or die "can't mkdir $tmpdir/tmp: $!";
    +
  • +
  • + Always check the return codes of system calls. Good error messages should go to STDERR, include which program caused the problem, what the failed system call and arguments were, and (VERY IMPORTANT) should contain the standard system error message for what went wrong. Here's a simple but sufficient example: +

    始终检查系统调用的返回值。有用的出错信æ¯åº”该输出到STDERR,包括哪个程åºå‡ºäº†é”™ï¼Œå“ªä¸ªè°ƒç”¨æœ‰é—®é¢˜ï¼Œå‚数是什么,而且(éžå¸¸é‡è¦ï¼ï¼‰è¦åŒ…括标准的系统错误信æ¯ã€‚一下是一个简å•ä¸è¿‡å®Œæ•´çš„例å­ï¼š

    +
        opendir(D, $dir)     or die "can't opendir $dir: $!";
    +
  • +
  • + Line up your transliterations when it makes sense: +
        tr [abc]
    +       [xyz];
    +

    如æžœå¯ä»¥çš„è¯ï¼Œå­—符映射应该对é½ã€‚

    +
  • +
  • Think about reusability. Why waste brainpower on a one-shot when you might want to do something like it again? Consider generalizing your code. Consider writing a module or object class. Consider making your code run cleanly with use strict and use warnings (or -w) in effect. Consider giving away your code. Consider changing your whole world view. Consider... oh, never mind.

    考虑一下å¯é‡ç”¨æ€§ï¼Œå½“ä½ å¯èƒ½ä¼šå†ç”¨åˆ°å®ƒçš„时候,为什么浪费精力写一次性的程åºå‘¢ï¼Ÿæ‰©å±•ä½ çš„程åºï¼Œå¹¶è€ƒè™‘一下写一个模å—或者类。看看能å¦åœ¨use strictuse warnings(或B -w<>)下è¿è¡Œä½ çš„程åºã€‚试试看å‘布你的程åºï¼Œè¯•è¯•çœ‹æ”¹å˜ä½ çš„世界观。试试看。。。oh,还是算了。

  • +
  • Be consistent.

    坚æŒä¸æ‡ˆã€‚

  • +
  • Be nice.

    做个好人。

  • +
+

TRANSLATORS

+

周æ° "klaus" <zhoujie@fudan.edu.cn> "flw" <flw@cpan.org>

+

中国perlå会: www.perlchina.org

+ + diff --git a/POD/CN_html/perlunitut.html b/POD/CN_html/perlunitut.html new file mode 100644 index 0000000..252c181 --- /dev/null +++ b/POD/CN_html/perlunitut.html @@ -0,0 +1,88 @@ + + + + perlunitut + + + + +

NAME

+

perlunitut - Perl万国ç æŒ‡å—

+

DESCRIPTION

+

编程语言åªèƒ½å¤„ç†ç®€å•å­—符的日å­ä¸€åŽ»ä¸å¤è¿”了ï¼çŽ°ä»£ç¨‹åºå¿…须能够和那些“有趣 çš„â€é‡éŸ³å­—æ¯ä»¥åŠè¯¸å¦‚欧洲符å·ä¸€æ ·çš„字符打交é“。这æ„味ç€ç¨‹åºå‘˜è¦å½¢æˆä¸€ç§æ–° çš„ä¹ æ€§ï¼Œç¼–å†™èƒ½å¤Ÿå¤„ç† Unicode 的软件并ä¸å›°éš¾ï¼Œä½†çš„确需è¦ä¸€äº›è§„范,æ‰èƒ½æŠŠ 这件事情åšå¥½åšå¯¹ã€‚

+

要了解字符集和字符编ç ï¼Œéœ€è¦çŸ¥é“的很多。最好你能花一天时间æ¥å­¦ä¹ è¿™äº›ï¼Œä½† 对于基础知识,几分钟时间就足够了。

+

然而这些知识也ä¸ç®—很“基础â€ã€‚这里å‡è®¾ä½ å·²ç»æ‡‚å¾—å­—èŠ‚å’Œå­—ç¬¦ä¹‹é—´çš„åŒºåˆ«ï¼ŒçŸ¥é“ æœ‰è®¸å¤šä¸åŒçš„字符集和编ç ï¼Œå¹¶ä¸”你的程åºè¦å¾ˆæ˜Žç¡®çš„区分它们。推è的阅读物为 “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)†作者 Joel Spolsky, http://joelonsoftware.com/articles/Unicode.html.

+

这篇指å—使用通用è¯æ±‡ï¼Œç®€å•ä¸”有é™ä»‹çš„ç»äº† Perl æ供的,与字符串相关的特性 。对于大多数项目,这些信æ¯åº”该已ç»è¶³å¤Ÿäº†ã€‚

+

定义

+

在开始时将一些概念弄清楚éžå¸¸é‡è¦ã€‚这也是本篇指å—最é‡è¦çš„部分。这里的æä¾› çš„ä¿¡æ¯å¯èƒ½å’Œä½ ä¹‹å‰åœ¨ç½‘络上找到的相冲çªï¼Œæœ€å¯èƒ½çš„原因是:它们大部分都错了 。

+

你å¯èƒ½è¦é‡è¯»è¿™ä¸€æ•´èŠ‚几次

+

万国ç (Unicode)

+

Unicode 是一个字符集,它æ供了容纳字符的空间。字符的åºæ•°å€¼å«åš码ä½ (code point)。(实际上,ç ä½å’Œå­—符之间的区别已ç»å¾ˆæ¨¡ç³Šäº†ï¼Œè¿™ä¸¤ä¸ªæœ¯è¯­ç»å¸¸ 互用。)

+

这世界上有很多很多很多ç ä½ï¼Œä½†è®¡ç®—机以字节为å•ä½å·¥ä½œï¼Œä¸€ä¸ªå­—节自åªèƒ½æä¾› 256个值。万国ç ä¸­åŒ…å«çš„字符比这多多了,所以你必须使用æŸç§æ–¹æ³•æ¥èŽ·å¾—这些 字符。

+

万国ç å¯ä»¥ä½¿ç”¨è®¸å¤šç§ç¼–ç æ–¹å¼ç¼–ç ï¼Œå…¶ä¸­ UTF-8 用得最为广泛。在一ç§ä¸‡å›½ç  ç¼–ç ä¸­ï¼Œå¤šå­—节的å­åºåˆ—å¯ä»¥ç”¨æ¥å­˜å‚¨ä¸€ä¸ªç ä½ï¼Œæˆ–者说:字符。

+

UTF-8

+

UTF-8 是一ç§ä¸‡å›½ç ç¼–ç æ–¹å¼ã€‚很多人认为万国ç å’Œ UTF-8 是åŒä¸€ä¸ªä¸œè¥¿ï¼Œå®ž 际上并ä¸æ˜¯ã€‚ç¼–ç æ–¹å¼è¿˜æœ‰æ›´å¤šï¼Œä½†å¤§åŠä¸ªä¸–界都在以 UTF-8 为标准。

+

UTF-8 çš„å‰128个ç ä½å’Œ ASCII ç¼–ç ä¸€æ ·ã€‚一个字节容纳一个字符。所有的其他字 符都使用了一ç§å¤æ‚的方法编ç æˆä¸¤ä¸ªæˆ–者更多(最高6)字节。幸è¿çš„是,Perl 替我们åšäº†è¿™ä¸€å·¥ä½œï¼Œæ‰€ä»¥æˆ‘们ä¸å¿…担心这一点。

+

文本串(字符串)

+

文本串(Text strings),或者字符串(character strings)由字符组æˆã€‚它 和字节没关系,和编ç ä¹Ÿæ²¡å…³ç³»ã€‚字符就是字符而已。

+

对于一个文本串,你å¯ä»¥åšä¸€äº›æ“作,比如:

+
    $text =~ s/foo/bar/;
+    if ($string =~ /^\d+$/) { ... }
+    $text = ucfirst $text;
+    my $character_count = length $text;
+

字符的值(ordchr)是对应的万国ç ç ä½ã€‚

+

二进制串(字节串)

+

二进制串(Binary strings)字节串(byte strings)由字节组æˆã€‚这里没有 字符,åªæœ‰å­—èŠ‚ã€‚æ‰€æœ‰ä¸Žå¤–ç•Œï¼ˆä»»ä½•ä½ å½“å‰ Perl 进程之外的东西)的交æµéƒ½æ˜¯é€š 过二进制串æ¥å®žçŽ°ã€‚

+

在二进制串上,你å¯ä»¥åšè¿™äº›æ“作:

+
    my (@length_content) = unpack "(V/a)*", $binary;
+    $binary =~ s/\x00\x0F/\xFF\xF0/;  # 给胆å­å¤§çš„ :)
+    print {$fh} $binary;
+    my $byte_count = length $binary;
+

编ç 

+

编ç (作动è¯ï¼‰æ˜¯ä»Ž文本二进制的转æ¢ã€‚è¦ç»™æ–‡æœ¬ä¸²ç¼–ç ï¼Œä½ å¿…须给 出目标编ç ï¼Œæ¯”如 iso-8859 或 UTF-8。有些编ç å¹¶ä¸å®Œå…¨æ”¯æŒä¸‡å›½ç è§„范 ,比如 iso-8859("latin") 范围。那么在编ç è¿‡ç¨‹ä¸­ï¼Œä¼šä¸¢å¤±é‚£äº›ä¸‡å›½ç ä¸èƒ½ 代表的字符,

+

解ç 

+

解ç 是从二进制到文本的转æ¢ã€‚解ç æ—¶ï¼Œä½ å¿…须知é“ç¼–ç æ—¶ç”¨åˆ°çš„是哪ç§ç¼–ç  æ–¹å¼ã€‚最é‡è¦çš„是,二进制串必须能被解ç ã€‚试图把一张PNG图片解ç æˆæ–‡æœ¬ä¸²æ˜¯ ä¸çŽ°å®žçš„。

+

内部格å¼

+

Perl有它自己的内部格å¼,它用这ç§å†…部格å¼æ¥ç¼–ç æ–‡æœ¬ä¸²ï¼Œä½¿å…¶èƒ½ä¿å­˜åˆ°å†… 存里é¢ã€‚所有的文本串都是这ç§å†…部格å¼ã€‚事实上,它们从æ¥æ²¡æœ‰å…¶ä»–æ ¼å¼ã€‚

+

你ä¸éœ€è¦çŸ¥é“这是什么格å¼ï¼Œå› ä¸ºåœ¨ä½ è§£ç æˆ–者编ç çš„时候,其间的转æ¢ä¼šè‡ªåŠ¨è¿› 行。

+

你的新工具包

+

把下é¢å‡ è¡ŒåŠ å…¥åˆ°ä½ çš„标准头部中:

+
    use Encode qw(encode decode);
+

或则,如果你很懒,åªéœ€è¦ï¼š

+
    use Encode;
+

I/Oæµï¼ˆçœŸæ­£çš„5分钟指å—)

+

一个程åºå…¸åž‹çš„输入/输出æµå¦‚下:

+
    1. 收å–和解ç 
+    2. 处ç†
+    3. ç¼–ç å’Œè¾“出
+

如果你的输入是二进制,而且应该ä¿æŒä¸ºäºŒè¿›åˆ¶ï¼Œé‚£ä¹ˆä½ å½“然ä¸éœ€è¦æŠŠå®ƒè§£ç ä¸ºæ–‡ 本串。在其他所有情况下,你都应该将其解ç ã€‚

+

如果你ä¸çŸ¥é“æ•°æ®æ˜¯å¦‚何被编ç çš„,解ç ä¹Ÿä¸ä¼šå¾ˆå¯é ã€‚ä½ å¯ä»¥é€‰æ‹©çš„è¯ï¼Œä½¿ç”¨ UTF-8 标准化是个好主æ„。

+
    my $foo   = decode('UTF-8', get 'http://example.com/'); my $bar   =
+    decode('ISO-8859-1', readline STDIN);
+    my $xyzzy = decode('Windows-1251', $cgi->param('foo'));
+

处ç†è¿‡ç¨‹å°±åƒä½ ä»¥å‰æ‰€çŸ¥ä¸€æ ·ã€‚唯一的ä¸åŒæ˜¯ï¼Œä½ ä½¿ç”¨çš„是字符,而ä¸æ˜¯å­—节。当 你在使用如 substr 或 length 时,这一点éžå¸¸æœ‰ç”¨ã€‚

+

在文本串中没有字节,知é“这一点很é‡è¦ã€‚当然,Perl有它的内部格å¼ï¼Œç”¨æ¥åœ¨å†… 存中存储字符串,但请你忽略这一点。如果你需è¦åšä¸€äº›å…³äºŽå­—节数目的事情,你 最好把这些事情挪到步骤3,将字符串编ç ä¹‹åŽã€‚这样你æ‰èƒ½å‡†ç¡®çš„知é“目标串里 é¢æœ‰å¤šå°‘字节。

+

将文本串编ç æˆäºŒè¿›åˆ¶ä¸²çš„方法如下:

+
    $body = encode('UTF-8', $body);
+

如果你需è¦çŸ¥é“字符串字节的长度,此时就是最好的时侯。因为 $body 现在是 字节串了,length 会报告字节的数目,而ä¸æ˜¯å­—符的数目。字符数现在是未知 的,因为字符åªå­˜åœ¨äºŽæ–‡æœ¬ä¸²ã€‚

+
    my $byte_count = length $body;
+

如果你所使用的å议支æŒè®¾ç½®ä½ æ‰€ä½¿ç”¨çš„字符编ç ï¼Œé‚£ä¹ˆè¯·ä½¿ç”¨è¿™ä¸ªç‰¹æ€§ã€‚比如 E-mail å’Œ HTTP æ”¯æŒ MIME 头部,这样你å¯ä»¥ä½¿ç”¨ Content-Type 头部。它们 还å¯ä»¥æœ‰ Content-Length,用以表示字节的数目。如果已ç»çŸ¥é“了这个数 目,设置它永远是个好主æ„。

+
    "Content-Type: text/plain; charset=UTF-8",
+    "Content-Length: $byte_count"
+

总结

+

将你收到的所有东西解ç ï¼Œå°†ä½ å‘出的所有东西编ç ã€‚(如果是文本数æ®çš„è¯ã€‚)

+

Q and A (or FAQ)

+

读完这篇文档之åŽï¼Œä½ åº”该继续阅读 perlunifaq

+

致è°¢

+

Thanks to Johan Vromans from Squirrel Consultancy. His UTF-8 rants during the Amsterdam Perl Mongers meetings got me interested and determined to find out how to use character encodings in Perl in ways that don't break easily.

+

Thanks to Gerard Goossen from TTY. His presentation "UTF-8 in the wild" (Dutch Perl Workshop 2006) inspired me to publish my thoughts and write this tutorial.

+

Thanks to the people who asked about this kind of stuff in several Perl IRC channels, and have constantly reminded me that a simpler explanation was needed.

+

Thanks to the people who reviewed this document for me, before it went public. They are: Benjamin Smith, Jan-Pieter Cornet, Johan Vromans, Lukas Mai, Nathan Gray.

+

AUTHOR

+

Juerd Waalboer <#####@juerd.nl>

+

SEE ALSO

+

perlunifaq, perlunicode, perluniintro, Encode

+

TRANSLATORS

+

Woosley Xu. woosley.xu@gmail.com

+ + diff --git a/POD/CN_html/perlutil.html b/POD/CN_html/perlutil.html new file mode 100644 index 0000000..112852f --- /dev/null +++ b/POD/CN_html/perlutil.html @@ -0,0 +1,58 @@ + + + + perlutil + + + + +

NAME

+

perlutil - Perl å‘行版中的实用程åº

+

DESCRIPTION

+

Perl å‘行版除了 Perl 解释器外还在你的系统上安装了一系列的实用程åºã€‚其中 一些程åºä¹Ÿæ˜¯è¢« Perl å‘行版本身用于安装过程。本文档将列出所有的这些程 åºï¼Œè§£é‡Šå®ƒä»¬çš„用途,尽é‡æ供相关模å—文档的链接。

+

文æ¡£

+
perldoc

Perl 文档的主è¦ç•Œé¢æ˜¯ perldoc,ä½ å¯èƒ½å·²ç»çŸ¥é“了。perldoc å¯ä»¥ä»Žå½“ å‰ç›®å½•ä¸‹çš„任何文件ã€ç³»ç»Ÿä¸­å®‰è£…的模å—ã€æˆ–者标准文档(比如本文)中æå– å¹¶æ ¼å¼åŒ–里é¢çš„文档。使用 perldoc <name> å¯ä»¥å¾—到本文中æ到的任 何程åºçš„ä¿¡æ¯ã€‚

pod2man 和 pod2text

如果在终端中è¿è¡Œ perldoc,通常它是调用 pod2man æ¥è½¬æ¢ POD(Plain Old Documentation —— å‚è§ perlpod)为 manpage,然åŽè¿è¡Œ man æ¥æ˜¾ 示。如果ä¸èƒ½ä½¿ç”¨ man 命令,就使用 pod2text ,并输出到你喜欢的 pager。

pod2html 和 pod2latex

除了这两个,还有两个转æ¢ç¨‹åºï¼špod2html 能从 POD 中产生 HTML 页 é¢ï¼›pod2latex 能够产生 LaTeX 文件。

pod2usage

如果你想知é“怎样使用这里æ述的程åºï¼Œpod2usage å¯ä»¥åªæŠ½æ出“USAGEâ€éƒ¨ 分;一些程åºä¼šåœ¨ä½ ç”¨ -help è¿è¡Œç¨‹åºæ—¶è‡ªåŠ¨å¯¹è‡ªèº«è°ƒç”¨ pod2usage

podselect

pod2usage 是 podselect 的一个特例。它是一个从文档的 POD 里抽æ出 æŸä¸ªå字的部分。例如,就åƒç¨‹åºæœ‰â€œUSAGEâ€éƒ¨åˆ†ï¼ŒPerl 的模å—通常有 “SYNOPSISâ€éƒ¨åˆ†ï¼špodselect -s "SYNOPSIS" ... 将能从一个给定文件中抽 æ出这一部分。

podchecker

如果你è¦ç”¨ POD 写你自己的文档,podchecker 程åºå¯ä»¥ä¸ºä½ çš„标记检查错 误。

splain

splain 是 perldiag 的接å£ï¼ŒæŠŠä½ çš„错误信æ¯ç²˜è´´ç»™å®ƒï¼Œå®ƒå°±ä¼šå‘你解 释。

roffitall

roffitall 程åºä¸æ˜¯å®‰è£…在你的系统中,但是在你 Perl æºæ–‡ä»¶çš„ pod/ 目录下。它能将å‘行版中的文档转æ¢æˆ *roff æ ¼å¼ï¼Œç„¶åŽäº§ç”Ÿ PostScript 或者文本文件。

+

转æ¢å™¨

+

为了帮助你将é—留程åºè½¬æ¢æˆ Perl,我们有三个转æ¢è¿‡æ»¤å™¨ï¼š

+
+
a2p
+
+

a2p å°† awk 脚本转æ¢æˆ Perl 程åºã€‚例如,a2p -F: 对简å•çš„ awk 脚本 {print $2 将产生一个类似于这样的 Perl 程åºï¼š

+
    while (<>) {
+        ($Fld1,$Fld2) = split(/[:\n]/, $_, 9999);
+        print $Fld2;
+    }
+
+
s2p
+
+

同样,s2p å°† sed 脚本转æ¢æˆ Perl 程åºã€‚对 s/foo/bar 使用 s2p 将产生类似这样的代ç ï¼š

+
    while (<>) {
+        chomp;
+        s/foo/bar/g;
+        print if $printit;
+    }
+
+
find2perl
+
+

最åŽï¼Œfind2perl 用 File::Find 模å—å°† find å‘½ä»¤è½¬æ¢ æˆç­‰ä»·çš„ Perl 命令。例如,find2perl . -user root -perm 4000 -print 为 File::Find 产生这样的调用函数:

+
    sub wanted {
+        my ($dev,$ino,$mode,$nlink,$uid,$gid);
+        (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+        $uid == $uid{'root'}) &&
+        (($mode & 0777) == 04000);
+        print("$name\n");
+    }
+
+
+

除了这些转æ¢å…¶å®ƒè¯­è¨€çš„过滤器,pl2pm 程åºèƒ½å¸®ä½ å°† Perl 4 æ—§å¼ çš„åº“è½¬æ¢æˆæ–°å¼çš„ Perl5 模å—。

+

系统管ç†å‘˜

+
libnetcfg

运è¡Œ libnetcfg 命令æ¥æ˜¾ç¤ºæˆ–者更改 libnet çš„é…置。

+

开å‘

+

这里有一系列的程åºå¸®åŠ©ä½ å¼€å‘ Perl 程åºï¼Œç‰¹åˆ«æ˜¯ç”¨ C 扩展 Perl。

+
perlbug

推è使用 perlbug å‘å¼€å‘人员æ交 perl 解释器本身或者任何标准模å—中的 bug。在使用它æ交一个 bug å‰ï¼Œè¯·å…ˆé€šè¯»ä¸€é perlbug 的文档。

h2ph

在存在 XS 系统连接 C 库之å‰ï¼Œç¨‹åºå‘˜æ›¾ç»ä½¿ç”¨è¯»å– C 头文件的方法得到库中 的常é‡ã€‚ä½ å¯èƒ½è¿˜èƒ½çœ‹åˆ° require 'syscall.ph' 或者相似的代ç ï¼Œè¿™ä¸ª .ph 文件是对相应 .h 文件使用 h2ph 程åºæ¥åˆ›å»ºçš„。å‚考 h2ph 的文档æ¥èŽ·å¾—如何一次性转化多个头文件的方法。

c2ph 和 pstruct

c2ph å’Œ pstruct 都用于将 C 结构和è”åˆå£°æ˜Žè½¬æ¢æˆ Perl 代ç ï¼Œä¸ºåœ¨ Perl 中使用 C æä¾›å¦ä¸€ç§æ–¹æ³•ã€‚它们事实上是相åŒçš„程åºï¼Œä½†æ˜¯è°ƒç”¨çš„æ–¹æ³•ä¸ åŒä¼šæœ‰ä¸åŒçš„结果。现在,h2xs é€æ¸å–代了它们。

h2xs

h2xs å°† C 头文件转æ¢æˆ XS 模å—,然åŽå°½å¯èƒ½çš„为 C 库和 Perl 模å—æä¾› 粘åˆä»£ç ã€‚它对于创建纯 Perl 模å—也是很有用的。

dprofpp

Perl æ供了一个 profiler:Devel::DProf 模å—。dprofpp 程åºåˆ†æžè¿™ 个 profiler 的输出,然åŽå‘Šè¯‰ä½ å“ªä¸ªå‡½æ•°èŠ±è´¹äº†æœ€å¤šçš„è¿è¡Œæ—¶é—´ã€‚å‚è§ Devel::DProf

perlcc

perlcc 是实验中的 Perl 编译器的接å£ã€‚

+

SEE ALSO

+

perldoc, pod2man, perlpod, pod2html, pod2usage, podselect, podchecker, splain, perldiag, roffitall, a2p, s2p, find2perl, File::Find, pl2pm, perlbug, h2ph, c2ph, h2xs, dprofpp, Devel::DProf, perlcc

+

TRANSLATORS

+

YE Wenbin

+ + diff --git a/POD/CN_html/perlvar.html b/POD/CN_html/perlvar.html new file mode 100644 index 0000000..5406608 --- /dev/null +++ b/POD/CN_html/perlvar.html @@ -0,0 +1,572 @@ + + + + perlvar + + + + +

NAME

+

perlvar - Perl 预定义å˜é‡

+

DESCRIPTION

+

预定义å称

+

后é¢åˆ—出的å称对 Perl æ¥è¯´å…·æœ‰ç‰¹æ®Šå«ä¹‰ã€‚ 大多数标点å称都有åˆç†çš„助记方法或类似于在 shell 中的用法。 然而,如果你就是想用长å˜é‡å,那åªè¦åœ¨ç¨‹åºå¼€å¤´åŠ ä¸Š

+
    use English;
+

即å¯ã€‚这样会为所有短å称在当å‰åŒ…中创建长å称别å。 其中一些甚至还有中间å,一般是从 awk 借用过æ¥çš„。 一般æ¥è¯´ï¼Œå¦‚æžœä¸éœ€è¦ $PREMATCH,$MATCH å’Œ $POSTMATCH,那最好使用

+
    use English '-no_match_vars';
+

调用方å¼ï¼Œå› ä¸ºå®ƒèƒ½é¿å…在用正则表达å¼æ—¶å‡ºçŽ°æ•ˆçŽ‡é™ä½Žçš„æƒ…å†µã€‚è§ English

+

依赖当å‰è¢«é€‰ä¸­æ–‡ä»¶å¥æŸ„çš„å˜é‡å¯ä»¥é€šè¿‡åœ¨ IO::Handle 对象上调用åˆé€‚的对象方法æ¥è®¾ç½®ï¼Œ 但是这è¦æ¯”使用普通的内建å˜é‡æ•ˆçŽ‡ä½Žä¸€äº›ã€‚(下é¢çš„概括行里包å«çš„å•è¯ HANDLE å³æŒ‡ IO::Handle 对象。) 首先你è¦å£°æ˜Ž

+
    use IO::Handle;
+

然åŽå°±å¯ä»¥ç”¨

+
    method HANDLE EXPR
+

或者更安全的形å¼ï¼Œ

+
    HANDLE->method(EXPR)
+

每个方法都返回 IO::Handle 属性的旧值,åŒæ—¶æŽ¥å—一个å¯é€‰çš„ EXPR。 如果æ供了该å‚æ•°ï¼Œåˆ™å…¶æŒ‡å®šäº†æ‰€æ¶‰åŠ IO::Handle 属性的新值。如果ä¸æ供该å‚数, 大多数方法ä¸æ”¹å˜å½“å‰å€¼--除了 autoflush(),它会å‡å®šç»™å®šäº†å‚æ•° 1,ç¨æœ‰ä¸åŒã€‚

+

载å…¥ IO::Handle 类是一项代价高昂的æ“作,因此你该知é“如何使用常规的内建å˜é‡ã€‚

+

这些å˜é‡ä¸­çš„少数几个是“åªè¯»çš„â€ã€‚è¿™æ„味ç€å¦‚果直接或者通过引用间接å‘该å˜é‡èµ‹å€¼ï¼Œ 就会引起一个è¿è¡Œæ—¶å¼‚常。

+

在修改本文档中æ述的大部分特殊å˜é‡çš„缺çœå€¼æ—¶éƒ½éœ€è¦ç‰¹åˆ«å°å¿ƒã€‚多数情况下应该 在修改之å‰å±€éƒ¨åŒ–这些å˜é‡ï¼Œå¦‚æžœä¸è¿™ä¹ˆåšï¼Œå°±å¯èƒ½å½±å“ä¾èµ–于你所修改特殊å˜é‡ç¼º çœå€¼çš„其他模å—。下é¢æ˜¯ä¸€æ¬¡æ€§è¯»å…¥æ•´ä¸ªæ–‡ä»¶çš„一ç§æ­£ç¡®æ–¹æ³•ï¼š

+
    open my $fh, "foo" or die $!;
+    local $/; # enable localized slurp mode
+    my $content = <$fh>;
+    close $fh;
+

但下é¢çš„代ç å°±å¾ˆç³Ÿç³•ï¼š

+
    open my $fh, "foo" or die $!;
+    undef $/; # enable slurp mode
+    my $content = <$fh>;
+    close $fh;
+

因为一些模å—å¯èƒ½æƒ³ä»¥é»˜è®¤çš„“行模å¼â€ä»Žæ–‡ä»¶ä¸­è¯»å–æ•°æ®ï¼Œè€Œä¸€æ—¦æˆ‘ä»¬åˆšæ‰ åˆ—å‡ºçš„ä»£ç å¾—到执行,在åŒä¸€ä¸ª Perl 解释器内è¿è¡Œçš„所有其他代ç è¯»åˆ°çš„ $/ 全局值都会被改å˜ã€‚

+

通常,在局部化一个å˜é‡æ—¶æ€»æ˜¯æƒ³è®©å½±å“é™åˆ¶åœ¨å°½å¯èƒ½å°çš„范围内,因此 应该自己建立一个 {} å—,除éžä½ å·²ç»å¤„于æŸäº›å°çš„ {} å—内。例如:

+
    my $content = '';
+    open my $fh, "foo" or die $!;
+    {
+        local $/;
+        $content = <$fh>;
+    }
+    close $fh;
+

下é¢æ˜¯ä»£ç å¤±æŽ§çš„一个例å­ï¼š

+
    for (1..5){
+        nasty_break();
+        print "$_ ";
+    }
+    sub nasty_break {
+        $_ = 5;
+        # do something with $_
+    }
+

你å¯èƒ½å¸Œæœ›ä¸Šè¿°ä»£ç æ‰“å°å‡ºï¼š

+
    1 2 3 4 5
+

但实际上得到的å´æ˜¯ï¼š

+
    5 5 5 5 5
+

为什么?因为 nasty_break() 修改了 $_ 而没有事先将其局部化。 改正方法是增加 local():

+
        local $_ = 5;
+

虽然在这样一个短å°çš„例å­é‡Œå¾ˆå®¹æ˜“å‘现问题,但在更å¤æ‚的代ç ä¸­ï¼Œå¦‚æžœä¸ å¯¹ç‰¹æ®Šå˜é‡è¿›è¡Œå±€éƒ¨åŒ–更改就是在自找麻烦。

+

下列内容按照先标é‡å˜é‡ã€åŽæ•°ç»„ã€æœ€åŽæ•£åˆ—的顺åºæŽ’列。

+
+
$ARG
+
+
$_
+
+

默认的输入和模å¼æœç´¢ç©ºé—´ã€‚下é¢çš„几对代ç éƒ½æ˜¯ç­‰åŒçš„:

+
    while (<>) {...}    # equivalent only in while!
+    while (defined($_ = <>)) {...}
+
+    /^Subject:/
+    $_ =~ /^Subject:/
+
+    tr/a-z/A-Z/
+    $_ =~ tr/a-z/A-Z/
+
+    chomp
+    chomp($_)
+

以下是几处å³ä½¿æ²¡æœ‰å†™æ˜Ž Perl 也会å‡å®šä½¿ç”¨ $_ 的地方:

+
    +
  • 各ç§å•ç›®å‡½æ•°ï¼ŒåŒ…æ‹¬åƒ ord() å’Œ int() 这样的函数以åŠé™¤ -t 以外所有的文件 测试æ“作 (-f-d),-t 默认æ“作 STDIN。
  • +
  • 各ç§åˆ—表函数,例如 print() å’Œ unlink()。
  • +
  • 没有使用 =~ è¿ç®—符时的模å¼åŒ¹é…æ“作 m//s/// å’Œ tr///
  • +
  • 在没有给出其他å˜é‡æ—¶æ˜¯ foreach 循环的默认迭代å˜é‡ã€‚
  • +
  • grep() å’Œ map() 函数的éšå«è¿­ä»£å˜é‡ã€‚
  • +
  • while 仅有唯一æ¡ä»¶ï¼Œä¸”该æ¡ä»¶æ˜¯å¯¹ <FH> æ“作的结果进行测试时,$_ 就是存放输入记录的默认ä½ç½®ã€‚除了 while 测试æ¡ä»¶ä¹‹å¤–ä¸ä¼šå‘生这ç§æƒ…况。
  • +
+

(助记:下划线在特定æ“作中是å¯ä»¥çœç•¥çš„。)

+
+
+
$a
$b

是使用 sort() 时的特殊包å˜é‡ï¼Œå‚è§ "sort" in perlfunc。 由于这一特殊性,$a å’Œ $b å³ä½¿åœ¨ç”¨äº† strict 'vars' 指示符以åŽä¹Ÿä¸éœ€è¦å£°æ˜Ž(用 use vars 或者 our())。 如果想è¦åœ¨ sort() 的比较å—或者函数中使用它们,就ä¸è¦ç”¨ my $a 或 my $b 将其è¯æ³•åŒ–。

+
+
$<digits>
+

含有上次模å¼åŒ¹é…中æ•èŽ·æ‹¬å·é›†åˆæ‰€å¯¹åº”çš„å­æ¨¡å¼ï¼Œä¸åŒ…括已ç»é€€å‡ºçš„嵌套 å—中匹é…的模å¼ã€‚(助记:类似 \digits。) 这些å˜é‡å…¨éƒ½æ˜¯åªè¯»çš„,对于 当å‰å—æ¥è¯´å…·æœ‰åŠ¨æ€ä½œç”¨åŸŸã€‚

+
$MATCH
+
+
$&
+

含有上次æˆåŠŸçš„模å¼åŒ¹é…所匹é…到的字符串(ä¸åŒ…括任何éšè—在å—中的匹é…æˆ–å½“å‰ å—所包围的 eval())。(助记:åŒä¸€äº›ç¼–辑器中的 & 类似。) 该å˜é‡æ˜¯åªè¯»çš„, 对于当å‰å—æ¥è¯´å…·æœ‰åŠ¨æ€ä½œç”¨åŸŸã€‚

在程åºä¸­ä»»ä½•åœ°æ–¹ä½¿ç”¨è¯¥å˜é‡éƒ½ä¼šä½¿æ‰€æœ‰æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…产生å¯è§‚的效率é™ä½Žã€‚ å‚è§ "BUGS"

+
$PREMATCH
+
+
$`
+

含有上次æˆåŠŸçš„模å¼åŒ¹é…内容之å‰çš„字符串(ä¸åŒ…括任何éšè—在å—中的匹é…æˆ–å½“å‰ å—所包围的 eval)。(助记:` 常常出现在引起的字符串之å‰ã€‚) 该å˜é‡æ˜¯åªè¯»çš„。

在程åºä¸­ä»»ä½•åœ°æ–¹ä½¿ç”¨è¯¥å˜é‡éƒ½ä¼šä½¿æ‰€æœ‰æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…产生å¯è§‚的效率é™ä½Žã€‚ å‚è§ "BUGS"

+
$POSTMATCH
+
+
$'
+
+

含有上次æˆåŠŸçš„模å¼åŒ¹é…内容之åŽçš„字符串(ä¸åŒ…括任何éšè—在å—中的匹é…æˆ–å½“å‰ å—所包围的 eval())。(助记:' 常常跟在引起的字符串之åŽã€‚) 例如:

+
    local $_ = 'abcdefghi';
+    /def/;
+    print "$`:$&:$'\n";         # prints abc:def:ghi
+

该å˜é‡åªè¯»ä¸”对于当å‰å—具有动æ€ä½œç”¨åŸŸã€‚

+

在程åºä¸­ä»»ä½•åœ°æ–¹ä½¿ç”¨è¯¥å˜é‡éƒ½ä¼šä½¿æ‰€æœ‰æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…产生å¯è§‚的效率é™ä½Žã€‚ å‚è§ "BUGS"

+
+
$LAST_PAREN_MATCH
+
+
$+
+
+

含有上次æˆåŠŸçš„æœç´¢æ¨¡å¼ä¸­æœ€åŽä¸€ä¸ªæ‹¬å·åŒ¹é…的文本。在无法知é“å¯é€‰æ¨¡å¼é›†ä¸­ 到底哪一个匹é…æˆåŠŸæ—¶ï¼Œè¯¥å˜é‡æ˜¯éžå¸¸æœ‰ç”¨çš„。例如:

+
    /Version: (.*)|Revision: (.*)/ && ($rev = $+);
+

(助记:积æžä¸€ç‚¹å„¿å‘å‰çœ‹ã€‚)(译注:“积æžâ€ä¸Žâ€œæ­£å·â€æ˜¯åŒä¸€ä¸ªå•è¯ã€‚) 该å˜é‡åªè¯»ä¸”相对于当å‰å—具有动æ€ä½œç”¨åŸŸã€‚

+
+
$^N
+
+

含有上一次æˆåŠŸæœç´¢æ¨¡å¼ä¸­æœ€è¿‘é—­åˆçš„组(å³æœ€å³è¾¹çš„å³æ‹¬å·æž„æˆçš„组)æ‰€åŒ¹é… çš„æ–‡æœ¬ã€‚(助记:最近闭åˆçš„(å¯èƒ½)嵌套的括å·ã€‚) (译注:嵌套的å•è¯ä¸º Nest。)

+

该å˜é‡ä¸»è¦ç”¨åœ¨ (?{...}) å—的内部,以便检查最近匹é…到的文本。例如, 为了有效地用一个å˜é‡($1$2 等等之外的å˜é‡)æ•èŽ·æ–‡æœ¬ï¼Œå¯ä»¥å°† (...) 替æ¢ä¸º

+
     (?:(...)(?{ $var = $^N }))
+

像这样设置并使用 $var 就能把你从计算括å·ä¸ªæ•°çš„烦æ¼ä¸­è§£æ”¾å‡ºæ¥äº†ã€‚

+

该å˜é‡å¯¹äºŽå½“å‰å—具有动æ€ä½œç”¨åŸŸã€‚

+
+
@LAST_MATCH_END
+
+
@+
+

该数组ä¿å­˜äº†å½“å‰æ´»åŠ¨çš„动æ€ä½œç”¨åŸŸä¸­æœ€è¿‘æˆåŠŸçš„å­åŒ¹é…结æŸå¤„çš„å移é‡ã€‚ $+[0] 为整个匹é…在字符串中结æŸå¤„çš„å移é‡ï¼Œè¿™åŒç”¨è¢«åŒ¹é…çš„å˜é‡è°ƒç”¨ pos 函数得到的值一样。该数组的第 n 个元素ä¿å­˜äº†ç¬¬ n 个å­åŒ¹é… çš„å移é‡ï¼Œå› æ­¤ $+[1] å°±æ˜¯ç´§æŽ¥ç€ $1 结æŸå¤„çš„å移é‡ï¼Œ$+[2] 是 ç´§æŽ¥ç€ $2 结æŸå¤„çš„å移é‡ï¼Œä»¥æ­¤ç±»æŽ¨ã€‚å¯ä»¥ç”¨ $#+ 得知最近æˆåŠŸçš„åŒ¹é… ä¸­æœ‰å¤šå°‘ä¸ªç»„ã€‚å‚è§ä¸º @- å˜é‡ç»™å‡ºçš„例å­ã€‚

+
$*
+

将其设为éžé›¶æ•´æ•°å€¼å°±å¯ä»¥è¿›è¡Œå­—符串内的多行匹é…,设为 0(或未定义值) 相当于告诉 Perl å¯ä»¥å‡å®šå­—符串都是å•è¡Œçš„,从而能进行模å¼åŒ¹é…的优化。当 $* 为 0 或未定义值时,对å«æœ‰å¤šä¸ªæ¢è¡Œç¬¦çš„字符串进行模å¼åŒ¹é…会产生很难 ç†è§£çš„结果。它默认为未定义值。(助记:* 匹é…很多东西。) 该å˜é‡åªå½±å“对 ^ å’Œ $ 的解释。å³ä½¿åœ¨ $* == 0 时也å¯ä»¥æœç´¢ä¸€ä¸ªå­—é¢çš„æ¢è¡Œç¬¦ã€‚

在现在的 Perl 里ä¸åº”使用 $*,在模å¼åŒ¹é…中å¯ä»¥ç”¨ /s å’Œ /m 修饰符å–代 它的功能。

$* 赋éžæ•°å€¼é‡ä¼šè§¦å‘一个警告(并使 $* 表现为 $* == 0),对 $* 赋数值é‡åˆ™ä¼šéšå«å¯¹å…¶åº”用 int

+
HANDLE->input_line_number(EXPR)
+
+
$INPUT_LINE_NUMBER
+
+
$NR
+
+
$.
+

为最åŽè®¿é—®çš„文件å¥æŸ„对应的当å‰è¡Œå·ã€‚

Perl 中æ¯ä¸ªæ–‡ä»¶å¥æŸ„都记录从其中读出的行数。(Perl 中行的概念也许和你ä¸ä¸€ 样,è¦çœ‹ $/ 的值是什么。) 当从æŸä¸ªæ–‡ä»¶å¥æŸ„中读出一行(通过 readline() 或 <>)或对其调用 tell() 或 seek() 时,$. å³æˆä¸ºé‚£ä¸ªå¥æŸ„çš„è¡Œ 计数器的别å。

你å¯ä»¥é€šè¿‡å‘ $. 赋值æ¥è°ƒæ•´è®¡æ•°å™¨ï¼Œä½†è¿™å¹¶ä¸ä¼šå®žé™…移动文件指针。 局部化 $. ä¸ä¼šä½¿å¯¹åº”文件å¥æŸ„的行计数器局部化,而åªä¼šå±€éƒ¨åŒ– $. 和文件å¥æŸ„的别å关系。

关闭文件å¥æŸ„时会å¤ä½ $.,但在没有 close() å°±é‡æ–°æ‰“开一个已打开的文件å¥æŸ„ æ—¶不会这样。更多细节å‚è§ "I/O Operators" in perlop<> 从ä¸æ˜¾å¼å…³é—­æ–‡ä»¶ï¼Œå› æ­¤è¡Œå·ä¼šåœ¨ ARGV 文件之间æŒç»­å¢žé•¿(ä¸è¿‡è¯·çœ‹çœ‹ "eof" in perlfunc 中的例å­)。

你还å¯ä»¥ç”¨ HANDLE->input_line_number(EXPR) 访问一个给定文件å¥æŸ„çš„ 行计数器,这样就无需担心最åŽè®¿é—®çš„是哪个å¥æŸ„了。

(助记:很多程åºç”¨â€œ.â€è¡¨ç¤ºå½“å‰è¡Œå·ã€‚)

+
IO::Handle->input_record_separator(EXPR)
+
+
$INPUT_RECORD_SEPARATOR
+
+
$RS
+
+
$/
+
+

为输入记录分隔符,默认为æ¢è¡Œç¬¦ã€‚该å˜é‡ä¼šå½±å“ Perl 对“行â€è¿™ä¸€æ¦‚念 çš„ç†è§£ã€‚其功能类似于 awk 中的 RS å˜é‡ï¼Œåœ¨è¢«è®¾ç½®ä¸ºç©ºå­—符串时åŒæ · 会将空白行作为终止标志。(空白行ä¸èƒ½å«æœ‰ä»»ä½•ç©ºæ ¼æˆ–制表符。) ä½ å¯ä»¥å°†å…¶ 设置为å«æœ‰å¤šä¸ªå­—符的字符串,以匹é…多字符的终止标志;也å¯ä»¥è®¾ä¸º undef 以便一直读到文件结æŸã€‚当文件å«æœ‰è¿žç»­çš„空白行时,把它设为 "\n\n" 和设为 "" 有少许ä¸åŒï¼šè®¾ä¸º "" 会把两个或更多连续的空白行视为å•ä¸ª 空白行;而设为 "\n\n" 则åªæ˜¯ç›²ç›®åœ°å‡å®šå…¶åŽè¾“入的字符属于下一段,å³ä½¿ 这些字符是æ¢è¡Œç¬¦ä¹Ÿä¸€æ ·ã€‚(助记:在引用诗å¥æ—¶ä¼šç”¨ / 作为行间的分隔。)

+
    local $/;           # enable "slurp" mode
+    local $_ = <FH>;    # whole file now here
+    s/\n[ \t]+/ /g;
+

切记:$/ 的内容是一个字符串,而ä¸æ˜¯æ­£åˆ™è¡¨è¾¾å¼ã€‚awk 得在æŸäº›æ–¹é¢æ”¹è¿› 一下了。:-)

+

$/ 设为整数ã€å­˜æœ‰æ•´æ•°çš„æ ‡é‡æˆ–å¯è½¬æ¢æˆæ•´æ•°çš„æ ‡é‡è¿™äº›å€¼çš„引用时,Perl 会å°è¯•è¯»å…¥è®°å½•è€Œä¸æ˜¯è¡Œï¼Œæœ€å¤§è®°å½•é•¿åº¦å°±æ˜¯å¼•ç”¨çš„那个整数。因此这段代ç ï¼š

+
    local $/ = \32768; # or \"32768", or \$var_containing_32768
+    open my $fh, $myfile or die $!;
+    local $_ = <$fh>;
+

会从 FILE 读å–一æ¡ä¸é•¿äºŽ 32768 字节的记录。如果你ä¸æ˜¯åœ¨è¯»å–一个é¢å‘记录 的文件(或者所用的 OS 没有é¢å‘记录的文件类型),那很å¯èƒ½æ¯æ¬¡è¯»å–都得到一 æ•´å—çš„æ•°æ®ã€‚è‹¥æŸæ¡è®°å½•æ¯”你所设置的记录长度还大,就会把该记录拆æˆè‹¥å¹²ç‰‡ 返回。

+

在 VMS 上,记录读å–是用 sysread 的等价物完æˆçš„,因此最好ä¸è¦åœ¨åŒä¸€ä¸ª 文件上混åˆä½¿ç”¨è®°å½•å’Œéžè®°å½•è¯»ã€‚(è¿™ä¸å¤ªå¯èƒ½æˆä¸ºé—®é¢˜ï¼Œå› ä¸ºä»»ä½•ä½ æƒ³ä»¥è®°å½•æ¨¡å¼ 读å–的文件也许都ä¸èƒ½åœ¨è¡Œæ¨¡å¼ä¸‹ç”¨ã€‚) éž VMS 系统用普通 I/O 进行读å–,因此 在一个文件中混åˆè®°å½•å’Œéžè®°å½•è¯»æ˜¯å®‰å…¨çš„。

+

参è§ "Newlines" in perlport ä»¥åŠ $.

+
+
HANDLE->autoflush(EXPR)
+
+
$OUTPUT_AUTOFLUSH
+
+
$|
+

若将该å˜é‡è®¾ä¸ºéžé›¶å€¼ï¼Œå°±ä¼šç«‹åˆ»å¼ºåˆ¶è¿›è¡Œåˆ·æ–°ï¼Œå¹¶ä¸”当å‰é€‰ä¸­çš„输出通é“在æ¯æ¬¡ 打å°æˆ–写之åŽéƒ½ä¼šè¿›è¡Œåˆ·æ–°ã€‚默认值为 0 (ä¸ç®¡é€‰ä¸­çš„通é“实际上是å¦è¢«ç³»ç»Ÿæ‰€ç¼“冲, $| åªæ˜¯å‘Šè¯‰ä½  Perl 是å¦åœ¨æ¯æ¬¡å†™å®Œä¹‹åŽæ˜¾å¼åˆ·æ–°)。典型情况下,若 STDOUT 的输出是终端则是行缓冲的,å¦åˆ™å°±æ˜¯å—缓冲。设置该å˜é‡åœ¨å‘管é“或套接字输出 时很有用,比如你正在 rsh 下è¿è¡Œä¸€ä¸ª Perl 程åºå¹¶ä¸”想在输出时马上就能看到 输出内容。该å˜é‡ä¸å½±å“输入缓冲。关于输入缓冲请å‚è§ "getc" in perlfunc。 (助记:when you want your pipes to be piping hot.)

+
IO::Handle->output_field_separator EXPR
+
+
$OUTPUT_FIELD_SEPARATOR
+
+
$OFS
+
+
$,
+

为 print 的输出域分隔符。通常 print ä¸ç»ä»»ä½•ä¿®é¥°å°±è¾“出它的å‚æ•°ï¼Œè¦ å¾—åˆ°æ›´åƒ awk 的行为,å¯ä»¥å°†è¯¥å˜é‡è®¾ç½®æˆå’Œ awk çš„ OFS å˜é‡ä¸€æ · ,以指定域之间打å°ä»€ä¹ˆã€‚(助记:当 print 语å¥é‡Œæœ‰â€œ,â€æ—¶ä¼šæ‰“å°çš„东西。)

+
IO::Handle->output_record_separator EXPR
+
+
$OUTPUT_RECORD_SEPARATOR
+
+
$ORS
+
+
$\
+

为 print 的输出记录分隔符。通常 print 简å•åœ°åŽŸæ ·è¾“出它的å‚数,ä¸å¢žåŠ  任何结尾的æ¢è¡Œç¬¦æˆ–其他表å¾è®°å½•ç»“æŸçš„字符串。è¦å¾—åˆ°æ›´åƒ awk 的行为, å¯ä»¥å°†è¯¥å˜é‡è®¾ä¸ºåŒ awk çš„ ORS å˜é‡ä¸€æ ·ï¼Œä»¥æŒ‡å®šåœ¨ print 的结尾输出 什么。(助记:设置 $\ 而ä¸æ˜¯åœ¨ print 结尾加“\nâ€ã€‚å¦å¤–,它长得和 $/ 很åƒï¼Œä½†å´æ˜¯ä½ ä»Ž Perl 那里拿“回â€çš„东西。) (译注:“回â€åŽŸæ–‡ä¸º å•è¯â€œbackâ€ï¼Œè¿˜æŒ‡ä»£åæ–œæ â€œbackslashâ€ï¼Œèµ·ä¸€è¯­åŒå…³ä½œç”¨ã€‚)

+
$LIST_SEPARATOR
+
+
$"
+

该å˜é‡åŒ $, 类似,但应用于å‘åŒå¼•å·å¼•èµ·çš„字符串(或类似的内æ’字符串) 中内æ’数组和切片值的场åˆã€‚默认为一个空格。(助记:我觉得显而易è§ã€‚)

+
$SUBSCRIPT_SEPARATOR
+
+
$SUBSEP
+
+
$;
+
+

为模拟多维数组时的下标分隔符。如果你这样引用一个散列元素

+
    $foo{$a,$b,$c}
+

实际上æ„æ€å°±æ˜¯

+
    $foo{join($;, $a, $b, $c)}
+

但是别这么写

+
    @foo{$a,$b,$c}      # a slice--note the @
+

它çš„æ„æ€æ˜¯

+
    ($foo{$a},$foo{$b},$foo{$c})
+

默认为“\034â€ï¼ŒåŒ awk çš„ SUBSEP 一样。如果你的散列键包å«äºŒè¿›åˆ¶æ•°æ®ï¼Œ å¯èƒ½ $; 就没法包å«ä»»ä½•å¯é çš„值了。 (助记:逗å·(语法上的下标分隔符)是åŠä¸ªåˆ†å·ã€‚是啊,我知é“这完全没有说æœåŠ› ,但 $, å·²ç»è¢«ç”¨åšæ›´é‡è¦çš„用途了。)

+

请è€ƒè™‘åƒ perllol 里说明的那样使用“真正的â€å¤šç»´æ•°ç»„。

+
+
$#
+

为打å°æ•°å€¼æ—¶çš„输出格å¼ã€‚该å˜é‡æ˜¯ awk 中 OFMT å˜é‡ä¸€ä¸ªç²—糙的模仿å°è¯•ã€‚ ä¸è¿‡ç¡®å®žæœ‰æ®µæ—¶é—´ awk å’Œ Perl 在什么å¯ä»¥çœ‹æˆæ•°å€¼çš„概念上有所分歧。它的 åˆå§‹å€¼æ˜¯â€œ%.ngâ€ï¼Œn 是你所用系统上 float.h 中 DBL_DIG å®çš„值。 è¿™åŒ awk 的默认 OFMT 设置“%.6gâ€ä¸ä¸€æ ·ï¼Œå› æ­¤ä½ éœ€è¦æ˜¾å¼è®¾å®š $# 以便 得到和 awk 一样的结果。(助记:# 是数值标志。)

不建议使用 $# å˜é‡ã€‚

+
HANDLE->format_page_number(EXPR)
+
+
$FORMAT_PAGE_NUMBER
+
+
$%
+

为当å‰é€‰ä¸­çš„输出通é“的当å‰é¡µç ã€‚åŒæ ¼å¼é…åˆä½¿ç”¨ã€‚ (助记:% 是 nroff 中的页ç ã€‚)

+
HANDLE->format_lines_per_page(EXPR)
+
+
$FORMAT_LINES_PER_PAGE
+
+
$=
+

为当å‰é€‰ä¸­çš„输出通é“的当å‰é¡µé•¿åº¦(å¯æ‰“å°çš„行数)。默认为 60。 åŒæ ¼å¼é…åˆä½¿ç”¨ã€‚ (åŠ©è®°ï¼šç¬¦å· = 由两个水平行组æˆã€‚)

+
HANDLE->format_lines_left(EXPR)
+
+
$FORMAT_LINES_LEFT
+
+
$-
+

为当å‰é€‰ä¸­çš„输出通é“的页é¢æ®‹ç•™è¡Œæ•°ã€‚åŒæ ¼å¼é…åˆä½¿ç”¨ã€‚ (助记:页é¢è¡Œæ•° - 已打å°è¡Œæ•°ã€‚)

+
@LAST_MATCH_START
+
+
@-
+

$-[0] 是最近一次æˆåŠŸåŒ¹é…的起始å移é‡ã€‚ $-[n] 是由第 n 个å­æ¨¡å¼æ‰€åŒ¹é…çš„å­å­—符串的起始å移é‡ï¼Œ 若对应的å­æ¨¡å¼æ²¡æœ‰åŒ¹é…则å–为 undef。

因此对 $_ 进行匹é…之åŽï¼Œ$& å’Œ substr $_, $-[0], $+[0] - $-[0] 是一样的。类似地,若 $-[n] 已定义,则 $n åŒ substr $_, $-[n], $+[n] - $-[n] 是一样的,$+ 也和 substr $_, $-[$#-], $+[$#-] - $-[$#-] 相åŒã€‚å¯ä»¥ç”¨ $#- 找出最近一次æˆåŠŸåŒ¹é… 中最åŽä¸€ä¸ªåŒ¹é…çš„å­ç»„。与之相对的 $#+ 是那次匹é…所用正则表达å¼ä¸­ å­ç»„的数目,对应的是 @+

该数组存放当å‰æ´»åŠ¨çš„动æ€ä½œç”¨åŸŸä¸­æœ€è¿‘æˆåŠŸçš„å­åŒ¹é…开始处的å移é‡ã€‚ $-[0] 是整个匹é…在字符串中开始处的å移é‡ï¼Œæ•°ç»„中第 n 个元素 存有第 n 个å­åŒ¹é…çš„å移é‡ï¼Œå› æ­¤ $-[1] 是 $1 开始处的ä½ç§»ï¼Œ $-[2] 是 $2 开始处的ä½ç§»ï¼Œä»¥æ­¤ç±»æŽ¨ã€‚

在对æŸä¸ªå˜é‡ $var 进行匹é…åŽï¼š

$` å’Œ substr($var, 0, $-[0]) 相åŒ
$& å’Œ substr($var, $-[0], $+[0] - $-[0]) 相åŒ
$' å’Œ substr($var, $+[0]) 相åŒ
$1 å’Œ substr($var, $-[1], $+[1] - $-[1]) 相åŒ
$2 å’Œ substr($var, $-[2], $+[2] - $-[2]) 相åŒ
$3 å’Œ substr $var, $-[3], $+[3] - $-[3]) 相åŒ
+
HANDLE->format_name(EXPR)
+
+
$FORMAT_NAME
+
+
$~
+

为当å‰è¢«é€‰ä¸­è¾“出通é“的当å‰æŠ¥è¡¨æ ¼å¼å称。默认为文件å¥æŸ„å。(助记:$^ 的兄弟。)

+
HANDLE->format_top_name(EXPR)
+
+
$FORMAT_TOP_NAME
+
+
$^
+

为当å‰è¢«é€‰ä¸­è¾“出通é“的当å‰é¡µçœ‰æ ¼å¼å称。默认为文件å¥æŸ„ååŽåŠ  _TOP。 (助记:指å‘页眉。)

+
IO::Handle->format_line_break_characters EXPR
+
+
$FORMAT_LINE_BREAK_CHARACTERS
+
+
$:
+

是一组字符,字符串å¯ä»¥åœ¨è¿™äº›å­—符åŽæ–­è¡Œä»¥å¡«å……æ ¼å¼ä¸­çš„连续域(以 ^ 开始)。 默认为 " \n-",使字符串能在空白或连字符处断开。 (助记:诗中的“冒å·â€æ˜¯ä¸€è¡Œçš„一部分。)

+
IO::Handle->format_formfeed EXPR
+
+
$FORMAT_FORMFEED
+
+
$^L
+

退纸时格å¼åº”输出的内容。默认为 \f。

+
$ACCUMULATOR
+
+
$^A
+

write() 对 format() 行的累加器的当å‰å€¼ã€‚æ ¼å¼ä¼šè°ƒç”¨ formline() 并将其结果放入 $^A。在调用对应的格å¼ä¹‹åŽï¼Œwrite() å°† $^A 的内容打å°å‡ºæ¥å¹¶æ¸…空之。 因此你永远ä¸å¯èƒ½çœ‹åˆ° $^A 的内容,除éžè‡ªå·±ç›´æŽ¥è°ƒç”¨ formline() 并查看该å˜é‡ 。å‚è§ perlform å’Œ "formline()" in perlfunc

+
$CHILD_ERROR
+
+
$?
+
+

由最近的管é“关闭ã€å引å·(``)命令ã€æˆåŠŸè°ƒç”¨ wait() å’Œ waitpid() 或者 system() æ“作符返回的状æ€ä¿¡æ¯ã€‚它就是由 wait() 系统调用返回的 16 ä½çŠ¶æ€å­— (或是由其他信æ¯ç»„åˆè€Œæˆçš„类似值)。因此,å­è¿›ç¨‹çš„退出值实际上是 ($? >> 8),$? & 127 给出了导致进程结æŸçš„ä¿¡å·ä»£ç (如果存在), 而 $? & 128 会报告是å¦äº§ç”Ÿäº†å†…核转储。(åŠ©è®°ï¼šåŒ sh å’Œ ksh 类似。)

+

另外如果 C ä¸­æ”¯æŒ h_errno å˜é‡ï¼Œåœ¨ä»»æ„ gethost*() 函数失败时,该å˜é‡ 的值将会通过 $? 返回。

+

如果已ç»ä¸º SIGCHLD 安装了一个信å·å¤„ç†å™¨ï¼Œé‚£ä¹ˆåœ¨å¤„ç†å™¨ä¹‹å¤– $? 的值通常 是有问题的。

+

END å­ç¨‹åºé‡Œï¼Œ$? å«æœ‰å³å°†äº¤ç»™ exit() 的值。å¯ä»¥åœ¨ END å­ç¨‹åº 中修改 $? 以达到改å˜ç¨‹åºé€€å‡ºçŠ¶æ€çš„效果。例如:

+
    END {
+        $? = 1 if $? == 255;  # die would make it 255
+    } 
+

在 VMS 系统下,指示符 use vmsish 'status' 使得 $? å映实际的 VMS 退出 状æ€ï¼Œè€Œä¸æ˜¯é»˜è®¤çš„对 POSIX 状æ€çš„æ¨¡æ‹Ÿï¼›ç»†èŠ‚è§ "$?" in perlvms

+

另è§ 错误指示器

+
+
${^ENCODING}
+

为 Encode 对象的对象引用,用æ¥å°†æºä»£ç è½¬æ¢æˆç»Ÿä¸€ç ã€‚多äºæœ‰äº†è¯¥å˜é‡ï¼Œ ä½ çš„ Perl 脚本æ‰ä¸ä¼šè¢«å¼ºåˆ¶ä¸º UTF-8 ç¼–ç ã€‚默认为 undef。ç»å¯¹ä¸å»ºè®®å¯¹ 该å˜é‡è¿›è¡Œç›´æŽ¥æ“ä½œã€‚ç»†èŠ‚è§ encoding

+
$OS_ERROR
+
+
$ERRNO
+
+
$!
+
+

如果按数值使用该å˜é‡ï¼Œå°±ä¼šå¾—到 errno å˜é‡çš„当å‰å€¼ï¼›æ¢å¥è¯è¯´ï¼Œå¦‚æžœ æŸä¸ªç³»ç»Ÿæˆ–者库函数调用失败了,就会设置该å˜é‡ã€‚è¿™æ„å‘³ç€ $! 的值仅当 紧接在一个失è´¥之åŽæ—¶æ‰æœ‰æ„义:

+
    if (open(FH, $filename)) {
+        # Here $! is meaningless.
+        ...
+    } else {
+        # ONLY here is $! meaningful.
+        ...
+        # Already here $! might be meaningless.
+    }
+    # Since here we might have either success or failure,
+    # here $! is meaningless.
+

上è¿°çš„无æ„义代表任何东西:零ã€éžé›¶ã€undef。æˆåŠŸçš„系统或库函数 调用不会将该å˜é‡é‡ç½®ä¸ºé›¶ã€‚

+

If used as a string, yields the corresponding system error string. You can assign a number to $! to set errno if, for instance, you want "$!" to return the string for error n, or you want to set the exit value for the die() operator. (Mnemonic: What just went bang?) 若作为字符串使用,则会产生对应的系统错误字符串。å¯ä»¥å¯¹ $! 赋一个数 æ¥è®¾ç½® errno,这样就能用 "$!" 得到错误 n 对应的字符串了,也å¯ä»¥ 用æ¥è®¾ç½® die() è¿ç®—符所用的退出值。(助记:刚刚什么东西炸了?)

+

另è§ 错误指示器

+
+
%!
+

$! 设置为æŸä¸ªå€¼æ—¶ %! 的对应元素å³ä¸ºçœŸå€¼ã€‚例如,$!{ENOENT} 为真当且仅当 $! 的当å‰å€¼ä¸º ENOENT;也就是说,若最åŽçš„错误是 "No such file or directory"(或其他等价的东西:并ä¸æ˜¯æ‰€æœ‰æ“作系统都给出 完全一致的错误,当然也ä¸å¯èƒ½éƒ½æ˜¯åŒä¸€ç§è¯­è¨€)。è¦æ£€æŸ¥æŸä¸ªç‰¹å®šçš„键在你的系统 上是å¦æœ‰æ„义,å¯ä»¥ç”¨ exists $!{the_key};è¦å–å¾—åˆæ³•é”®çš„列表,å¯ä»¥ç”¨ keys %!。更多信æ¯è§ Errno,å¦å¤–从å‰é¢çš„æ述也å¯ä»¥å¾—出 $! 的有效 范围。

+
$EXTENDED_OS_ERROR
+
+
$^E
+

同当å‰æ“作系统相关的错误信æ¯ã€‚ç›®å‰è¯¥å˜é‡ä»…在 VMSã€OS/2 å’Œ Win32 (ä»¥åŠ MacPerl)ä¸‹åŒ $! 有所ä¸åŒã€‚在所有其他平å°ä¸Šï¼Œ$^E 总是和 $! 一样。

在 VMS 系统下,$^E 是最近一次系统错误的 VMS 状æ€å€¼ã€‚这比 $! æ供的关于系统错误的信æ¯æ›´ä¸ºè¯¦å°½ã€‚当 $! è¢«è®¾ç½®æˆ EVMSERR æ—¶ 该å˜é‡å°¤ä¸ºé‡è¦ã€‚

在 OS/2 系统下,$^E 被设置为最近一次通过 CRT 或直接通过 Perl 进行的 OS/2 API 调用所返回的错误代ç ã€‚

在 Win32 下,$^E 总是返回由 Win32 调用 GetLastError() 所报告 的错误信æ¯ï¼Œå®ƒæ述的是å‘生在 Win32 API 内部的最近一次错误。多数 特定于 Win32 的程åºä»£ç ä¼šé€šè¿‡ $^E 报告错误,而 ANSI C åŠç±» Unix 调用则会设置 errno,因此大部分å¯ç§»æ¤çš„ Perl 代ç éƒ½é€šè¿‡ $! 报告错误。

$! çš„æ述中æ到的警告一般也适用于 $^E。(助记:é¢å¤–的错误解释。) (译注:英文中“é¢å¤–â€çš„å•è¯ä¸ºâ€œExtraâ€ã€‚)

另è§ 错误指示器

+
$EVAL_ERROR
+
+
$@
+

最近一个 eval() è¿ç®—符返回的 Perl 语法错误消æ¯ã€‚ è‹¥ $@ 是空字符串,则最近一次 eval() 进行了正确的解æžå’Œæ‰§è¡Œ( 但是你所进行的æ“作å¯èƒ½å·²ç»æŒ‰ç…§é€šå¸¸çš„å½¢å¼å¤±è´¥äº†)。 (助记:语法错误å‘生“在â€å“ªé‡Œï¼Ÿ) (译注:符å·â€œ@â€ä¸ºè‹±æ–‡å•è¯â€œatâ€ç®€å†™ï¼Œæ„为“在……â€)

警告消æ¯ä¸ä¼šè¢«æ”¶é›†åœ¨è¯¥å˜é‡ä¸­ã€‚但你å¯ä»¥åƒåŽé¢æ述的那样,通过设置 $SIG{__WARN__} 自己建立一个例程æ¥å¤„ç†è­¦å‘Šã€‚

另è§ 错误指示器

+
$PROCESS_ID
+
+
$PID
+
+
$$
+

运行本脚本的 Perl 的进程å·ã€‚该å˜é‡åº”视为åªè¯»çš„,ä¸è¿‡åœ¨ fork() 调用 时会被改å˜ã€‚(助记:和 shell 一样。)

Linux 用户注æ„:在 Linux 下, C 函数 getpid() å’Œ getppid() 对 ä¸åŒçš„线程返回ä¸åŒçš„值。为了å¯ç§»æ¤ï¼Œè¯¥è¡Œä¸ºæ²¡æœ‰å映在 $$ 里,该å˜é‡ 的值在线程间ä¿æŒä¸å˜ã€‚如果你想调用底层的 getpid(),å¯ä»¥ä½¿ç”¨ CPAN æ¨¡å— Linux::Pid

+
$REAL_USER_ID
+
+
$UID
+
+
$<
+

本进程的实际 uid。(助记:如果你用了 setuid,那么这是你原æ¥çš„ uid。) å¯ä»¥ç”¨ POSIX::setuid() åŒæ—¶æ”¹å˜å®žé™… uid 和有效 uidã€‚ç”±äºŽæ”¹å˜ $< éœ€è¦ è¿›è¡Œç³»ç»Ÿè°ƒç”¨ï¼Œåœ¨æ›´æ”¹ä¹‹åŽåº”检查 $! 以å‘现å¯èƒ½äº§ç”Ÿçš„错误。

+
$EFFECTIVE_USER_ID
+
+
$EUID
+
+
$>
+
+

本进程的有效 uid。例:

+
    $< = $>;            # set real to effective uid
+    ($<,$>) = ($>,$<);  # swap real and effective uid
+

可以用 POSIX::setuid() åŒæ—¶æ”¹å˜æœ‰æ•ˆ uid 和实际 uid。更改 $> åŽéœ€è¦ 检查 $! 以å‘现å¯èƒ½äº§ç”Ÿçš„错误。

+

(助记:如果你用了 setuid,那么这是你è¦å˜æˆçš„ uid。) $< å’Œ $> ä»…åœ¨æ”¯æŒ setreuid() 的机器上æ‰èƒ½äº’æ¢ã€‚

+
+
$REAL_GROUP_ID
+
+
$GID
+
+
$(
+

本进程的实际 gid。如果你使用的机器支æŒåŒæ—¶å±žäºŽå¤šä¸ªç»„,则该å˜é‡ç»™å‡ºçš„是 被空格隔开的所在组列表。第一个数值是由 getgid() 返回的结果,åŽç»­çš„内容 是 getgroups() 返回的结果,其中å¯èƒ½æœ‰å’Œç¬¬ä¸€ä¸ªå€¼ç›¸åŒçš„项。

然而为了设置实际 gid,赋给 $( 的必须是å•ä¸ªæ•°å€¼ã€‚因此从 $( 得到的 值在没有强制为数值(例如åŒé›¶ç›¸åŠ )的情况下不应再赋给 $(

可以用 POSIX::setgid() åŒæ—¶æ”¹å˜å®žé™… gid 和有效 gid。更改 $( åŽéœ€è¦æ£€æŸ¥ $! 以便å‘现å¯èƒ½å‡ºçŽ°çš„错误。

(助记:圆括å·ç”¨æ¥å°†äº‹ç‰©分组。当使用 setgid 时,实际 gid 是你离å¼€的那个 组。)(译注:英文“离开â€å’Œâ€œå·¦â€éƒ½æ˜¯å•è¯â€œleftâ€ã€‚)

+
$EFFECTIVE_GROUP_ID
+
+
$EGID
+
+
$)
+

本进程的有效 gid。如果你使用的机器支æŒåŒæ—¶å±žäºŽå¤šä¸ªç»„,则该å˜é‡ç»™å‡ºçš„是被 空格隔开的所在组列表。第一个数值为 getegid() 的返回值,åŽç»­çš„值是 getgroups() 的返回值,其中å¯èƒ½æœ‰å’Œç¬¬ä¸€ä¸ªå€¼ç›¸åŒçš„项。

类似地,赋给 $) 的值也必须是一个空格隔开的数值列表。第一个数设置有效 gid,其余部分(若存在)则传给 setgroups()。è¦è¾¾åˆ°å‘ setgroups() 传递空列表 的效果,åªéœ€é‡å¤ä¸€é新设置的有效 gid;例如,è¦å°†æœ‰æ•ˆ gid 强制为 5 å¹¶å‘ setgroups() 传入空列表,就è¦è¿™ä¹ˆå†™ï¼š$) = "5 5"

可以用 POSIX::setgid() åŒæ—¶æ”¹å˜æœ‰æ•ˆ gid 和实际 gid (åªç”¨å•ä¸ªæ•°å€¼å‚æ•°)。 更改 $) åŽéœ€è¦å¯¹ $! 进行检查以便å‘现å¯èƒ½å‡ºçŽ°çš„错误。

(助记:圆括å·ç”¨æ¥分组事物。当使用 setgid 时,有效 gid 就是你需è¦çš„那个 组)(译注:原文为“that's right for youâ€ï¼Œéš¾ä»¥è¡¨è¾¾â€œrightâ€çš„å«ä¹‰ã€‚)

$<$>$( å’Œ $) åªèƒ½åœ¨æ”¯æŒå¯¹åº”çš„ set[re][ug]id() 例程的机器上进行设置。$( å’Œ $) åªèƒ½åœ¨æ”¯æŒ setregid() 的机器上互æ¢ã€‚

+
$PROGRAM_NAME
+
+
$0
+

包å«å½“å‰è¿è¡Œç¨‹åºå。

在一些(注æ„:ä¸æ˜¯å…¨éƒ¨)æ“ä½œç³»ç»Ÿä¸‹ï¼Œå‘ $0 赋值å¯ä»¥æ”¹å˜ ps 程åºæ‰€çœ‹åˆ° çš„å‚数域。æŸäº›å¹³å°ä¸Šä½ å¯èƒ½éœ€è¦ç”¨ç‰¹æ®Šçš„ ps 选项或其他的 ps æ‰èƒ½çœ‹åˆ° 这个改å˜ã€‚修改 $0 作为指示当å‰ç¨‹åºçŠ¶æ€çš„一ç§æ–¹æ³•ï¼Œè¦æ¯”用æ¥éšè—你在è¿è¡Œçš„ 程åºæ›´æœ‰ç”¨ã€‚(åŠ©è®°ï¼šåŒ sh å’Œ ksh 一样。)

注æ„ $0 的最大长度å—相关平å°çš„é™åˆ¶ã€‚多数æžç«¯æƒ…况下å¯èƒ½è¢«é™åˆ¶åœ¨åŽŸå§‹çš„ $0 所å æ®çš„空间之内。

在æŸäº›å¹³å°ä¸Šå¯èƒ½ä¼šé™„加一些填充字符(例如空格)在 ps 显示出的修改å称 之åŽã€‚有些平å°ä¸Šè¿™ç§å¡«å……会充满原å‚数域,并且ä¸å—你的控制(例如 Linux 2.2)。

BSD 用户注æ„:设置 $0 ä¸ä¼šå®Œå…¨æŠŠâ€œperlâ€ä»Ž ps(1) 的输出中抹去。例如, å°† $0 设置为 "foobar" å¯èƒ½äº§ç”Ÿ "perl: foobar (perl)"("perl: " å‰ç¼€å’Œ " (perl)"åŽç¼€æ˜¯å¦æ˜¾ç¤ºå‡ºæ¥ä¾èµ–于确切的 BSD ç§ç±»åŠç‰ˆæœ¬)。这是æ“作系统 的一个特性,Perl 没法改å˜å®ƒã€‚

在多线程脚本中 Perl 对所有线程等åŒè§†ä¹‹ï¼Œå› æ­¤ä»»ä½•çº¿ç¨‹éƒ½èƒ½æ›´æ”¹è‡ªå·±çš„ $0 副本,并且这一更改对 ps(1) 也是å¯è§çš„(å‡è®¾æ“作系统肯åˆä½œ)。注æ„其他线程 所看到的 $0 ä¸ä¼šè¢«æ”¹å˜ï¼Œå› ä¸ºå®ƒä»¬æœ‰è‡ªå·±çš„副本。

+
$[
+

数组第一个元素以åŠå­—符串中首个字符的索引å·ã€‚默认为 0,但ç†è®ºä¸Šä½ å¯ä»¥å°†å…¶ 设为 1 ,以使 Perl 在处ç†ä¸‹æ ‡æˆ–对 index() å’Œ substr() 函数求值时表现得更 åƒ awk(或 Fortran)。(助记:[ 代表下标开始。)

Perl 5 出现åŽï¼Œå‘ $[ 赋值被当作一个编译器指示符,因此ä¸ä¼šå½±å“任何其他文件 的行为。(这就是为什么你åªèƒ½èµ‹ç»™å®ƒç¼–译期常é‡çš„原因。) 强烈建议ä¸è¦ä½¿ç”¨è¯¥å˜é‡ã€‚

注æ„,ä¸åƒå…¶ä»–编译期指示符(例如 strict),对 $[ 的赋值对于åŒä¸€æ–‡ä»¶çš„外层è¯æ³• 作用域æ¥è¯´æ˜¯å¯è§çš„。然而你å¯ä»¥å¯¹å…¶ä½¿ç”¨ local(),从而将它的值严格é™å®šåœ¨å•ä¸ªè¯æ³• å—之内。

+
$]
+
+

Perl 解释器的版本 + è¡¥ä¸çº§åˆ« / 1000。该å˜é‡å¯ç”¨æ¥åˆ¤å®šä¸€ä¸ªè„šæœ¬æ˜¯å¦è¿è¡Œåœ¨æ°å½“版本 范围的 Perl 解释器上。(助记:该版本的 Perl 是å¦æ˜¯æ­£ç¡®çš„类别?)(译注:英文 “right bracketâ€å¯ä»¥è¡¨ç¤ºæ­£ç¡®çš„类别,字é¢æ„æ€åˆ™æ˜¯å³æ–¹æ‹¬å·ã€‚) 例:

+
    warn "No checksumming!\n" if $] < 3.019;
+

在è¿è¡Œçš„ Perl 解释器太è€æ—¶å¯¼è‡´å¤±è´¥çš„一ç§ç®€ä¾¿æ–¹æ³•å¯å‚è§ use VERSION å’Œ require VERSION 的文档

+

为了é¿å…浮点数的ä¸ç²¾ç¡®æ€§ï¼Œåœ¨æµ‹è¯•è¯¥å˜é‡æ—¶ä½ å¯èƒ½æ›´å¸Œæœ›ç”¨ä¸ç­‰æµ‹è¯• < å’Œ >,而ä¸æ˜¯åŒ…å«æœ‰ç›¸ç­‰çš„测试:<=== å’Œ >=

+

浮点数表示法有时会导致ä¸ç²¾ç¡®çš„数值比较结果。å¦ä¸€ç§å…许对 Perl 版本进行精确的字符串 æ¯”è¾ƒçš„çŽ°ä»£åŒ–è¡¨ç¤ºæ³•è¯·è§ $^V

+
+
$COMPILING
+
+
$^C
+

同开关 -c 相关è”的标志的当å‰å€¼ã€‚主è¦ç”¨äºŽ -MO=...,以å…许代ç åœ¨ç¼–译时改å˜è‡ªèº« è¡Œä¸ºï¼Œä¾‹å¦‚åœ¨ç¼–è¯‘æœŸå¤„ç† AUTOLOAD 而ä¸æ˜¯åƒå¹³æ—¶é‚£æ ·å»¶è¿Ÿè½½å…¥ã€‚è§ perlcc。设置 $^C = 1 åŒè°ƒç”¨ B::minus_c 类似。

+
$DEBUGGING
+
+
$^D
+

调试标志的当å‰å€¼ã€‚(助记:-D 开关的值。)å¯ä»¥è¯»å–或设置。åŒå®ƒçš„命令行等价物类似,你 å¯ä»¥ä½¿ç”¨æ•°å€¼æˆ–符å·å€¼ï¼Œä¾‹å¦‚ $^D = 10 å’Œ $^D = "st"

+
$SYSTEM_FD_MAX
+
+
$^F
+

系统文件æ述符最大数é‡ï¼Œé€šå¸¸ä¸º 2。系统文件æ述符会被传递到 exec() 出æ¥çš„ 进程里去,而数值高于它的文件æ述符则ä¸ä¼šã€‚å¦å¤–在 open() 时,若 open() 调用 失败系统文件æ述符会ä¿æŒä¸å˜ã€‚(普通文件æ述符在å°è¯• open() 之å‰ä¼šè¢«å…³é—­ã€‚) 文件æ述符的 exec 时关闭状æ€æ˜¯æ ¹æ®å¯¹åº”的文件ã€ç®¡é“或套接字打开时的 $^F 值æ¥å†³å®šçš„,而ä¸æ˜¯ exec() 时的 $^F 值。

+
$^H
+
+

警告:该å˜é‡åº”严格é™åˆ¶åœ¨å†…部使用。其存在性ã€è¡Œä¸ºä»¥åŠå†…容å¯èƒ½ä¸ç»æ醒就被改 å˜ã€‚

+

该å˜é‡åŒ…å« Perl 解释器的编译期æ示。在一个å—编译结æŸæ—¶è¯¥å˜é‡ä¼šæ¢å¤åˆ°è§£é‡Šå™¨å¼€å§‹ 编译那个å—时的值。

+

当 perl 开始解æžä»»ä½•æ供了è¯æ³•ä½œç”¨åŸŸçš„å—构造时(例如 eval 体ã€require 的文件 ã€å­ç¨‹åºä½“ã€å¾ªçŽ¯ä½“或æ¡ä»¶å—),$^H 的已有值会被ä¿å­˜ä¸‹æ¥ï¼Œä½†ä¸ä¼šå‘生å˜åŒ–。当 该å—的编译完æˆæ—¶ï¼Œ$^H æ¢å¤åˆ°ä¿å­˜çš„值。在ä¿å­˜å’Œæ¢å¤å…¶å€¼çš„两点之间,BEGIN å—中 执行的代ç å¯ä»¥ä»»æ„æ”¹å˜ $^H 的值。

+

该行为æ供了è¯æ³•ä½œç”¨åŸŸè¯­ä¹‰ï¼Œå¹¶è¢«åº”ç”¨åœ¨åƒ use strict 指示符这样的地方。

+

其值应为一个整数;ä¸åŒçš„ä½ä»£è¡¨ä¸åŒçš„指示标志。例如:

+
    sub add_100 { $^H |= 0x100 }
+
+    sub foo {
+        BEGIN { add_100() }
+        bar->baz($boon);
+    }
+

考虑在 BEGIN å—执行过程中å‘生了什么。此时 BEGIN å—å·²ç»é€šè¿‡ç¼–译,而 foo() 函数体尚未完æˆç¼–译。因此 $^H 的新值仅在 foo() 函数体编译时å¯è§ã€‚

+

将上é¢çš„ BEGIN å—替æ¢ä¸ºï¼š

+
    BEGIN { require strict; strict->import('vars') }
+

即演示了 use strict 'vars' 是如何实现的。下é¢æ˜¯åŒä¸€è¯æ³•æŒ‡ç¤ºç¬¦çš„一个æ¡ä»¶åŒ– 版本:

+
    BEGIN { require strict; strict->import('vars') if $condition }
+
+
%^H
+

警告:该å˜é‡åº”严格é™å®šåœ¨å†…部使用。其存在性ã€è¡Œä¸ºä»¥åŠå†…容å¯èƒ½ä¸ç»æ醒就被改å˜ã€‚

%^H 散列表æ供与 $^H 相åŒçš„作用域语法。这使其在实现è¯æ³•ä½œç”¨åŸŸå†…的指示符时éžå¸¸ 有用。

+
$INPLACE_EDIT
+
+
$^I
+

原地编辑扩展的当å‰å€¼ã€‚设置为 undef 时关闭原地编辑。(助记:-i 开关的值。)

+
$^M
+
+

默认情况下,内存耗尽是一个ä¸å¯æ•æ‰çš„致命错误。然而在适当编译的版本中, Perl å¯ä»¥å°† $^M 的内容用作 die() åŽçš„紧急内存池。å‡è®¾ä½ çš„ Perl 编译时使用 了 -DPERL_EMERGENCY_SBRK é€‰é¡¹ä»¥åŠ Perl 自己的 malloc。那么

+
    $^M = 'a' x (1 << 16);
+

将会分é…一个 64K 的缓冲区以备紧急情况时使用。如何打开该选项的相关信æ¯è¯·å‚è§ Perl å‘行版中的 INSTALL 文件。为了防止无æ„中使用这一高级特性,该å˜é‡æ²¡æœ‰ 对应的 English é•¿å。

+
+
$OSNAME
+
+
$^O
+

为å½“å‰ Perl 副本编译时所处的æ“作系统å称,在é…置过程中å³ç¡®å®šã€‚å…¶å€¼åŒ $Config{'osname'} 相åŒã€‚å¦è§ Config åŠ perlrun 中说明的 -V 命令行开关。

在 Windows å¹³å°ä¸‹ï¼Œ$^O 并ä¸å分有用:因为它总是 MSWin32,而无法表示出 95/98/ME/NT/2000/XP/CE/.NET 之间的区别。请用 Win32::GetOSName() 或 Win32::GetOSVersion() (è§ Win32 åŠ perlport) 区分这些å˜ç§ã€‚

+
${^OPEN}
+

由 PerlIO 使用的一个内部å˜é‡ã€‚是由 \0 字节分开的两部分组æˆçš„一个字符串, å‰ä¸€éƒ¨åˆ†æ述输入层,åŽä¸€éƒ¨åˆ†æ述输出层。

+
$PERLDB
+
+
$^P
+

供调试支æŒç”¨çš„内部å˜é‡ã€‚å…¶ä¸åŒä½æ‰€ä»£è¡¨çš„æ„义很å¯èƒ½æ”¹å˜ï¼Œä½†ç›®å‰è¡¨ç¤ºçš„是:

0x01

进å…¥/退出调试å­ç¨‹åºã€‚

0x02

逐行调试。

0x04

关闭优化。

0x08

为åŽç»­çš„交互检查预留更多数æ®ã€‚

0x10

保ç•™å­ç¨‹åºå®šä¹‰æ—¶æ‰€å¤„æºä»£ç è¡Œçš„ä¿¡æ¯ã€‚

0x20

启动时打开å•æ­¥è°ƒè¯•ã€‚

0x40

报告时用å­ç¨‹åºåœ°å€è€Œä¸æ˜¯å称。

0x80

还è¦æŠ¥å‘Š goto &subroutine

0x100

根æ®ç¼–译的ä½ç½®ä¸º eval æ供表现内容较多的“文件â€å。

0x200

根æ®ç¼–译的ä½ç½®ä¸ºåŒ¿åå­ç¨‹åºæ供表现内容较多的å称。

0x400

进å…¥/退出调试断言å­ç¨‹åºã€‚

某些ä½ä»…åŒç¼–译期相关,还有一些是è¿è¡ŒæœŸç›¸å…³çš„。这是一ç§æ–°æœºåˆ¶ï¼Œä»¥åŽå¯èƒ½ 会修改其细节。

+
$LAST_REGEXP_CODE_RESULT
+
+
$^R
+

上一次æˆåŠŸçš„ (?{ code }) 正则表达å¼æ–­è¨€(è§ perlre)的求值结果。 å¯ä»¥è¢«æ”¹å†™ã€‚

+
$EXCEPTIONS_BEING_CAUGHT
+
+
$^S
+
+

解释器当å‰çŠ¶æ€ã€‚

+
    $^S         状æ€
+    ---------   -------------------
+    undef       解æžæ¨¡å—/eval
+    true (1)    正在执行一个 eval
+    false (0)   其他
+

第一个状æ€ä¹Ÿå¯èƒ½åœ¨ $SIG{__DIE__} å’Œ $SIG{__WARN__} 处ç†ç¨‹åºå†…产生。

+
+
$BASETIME
+
+
$^T
+

程åºå¼€å§‹è¿è¡Œçš„时间,是从格林å¨æ²»æ ‡å‡†æ—¶åˆ»(1970 å¹´åˆ)开始的秒数。由 -M ã€-A å’Œ -C 文件测试所返回的结果是基于该值的。

+
${^TAINT}
+

反映污染模å¼æ˜¯å¦æ‰“开。1 表示打开(程åºç”¨ -T è¿è¡Œ),0 表示关闭,-1 表示仅 打开了污染警告(å³ä½¿ç”¨äº† -t 或 -TU)。

+
${^UNICODE}
+

反映了 Perl 的确切 Unicode 设置。关于其å¯èƒ½å€¼çš„更多信æ¯è¯·è§ perlrun 文档 中对 -C 开关的æ述。该å˜é‡åœ¨ Perl å¯åŠ¨æ—¶è¢«è®¾ç½®ï¼Œç„¶åŽå°±æ˜¯åªè¯»çš„了。

+
$PERL_VERSION
+
+
$^V
+
+

Perl 解释器的修订å·ã€ç‰ˆæœ¬å·ä»¥åŠå­ç‰ˆæœ¬å·ï¼Œç”±å…·æœ‰è¿™äº›åºæ•°çš„字符组æˆçš„字符串表示 。因此 Perl v5.6.0 中该å˜é‡ç­‰äºŽ chr(5) . chr(6) . chr(0) 且 $^V eq v5.6.0 会返回真值。注æ„该字符串值中的字符å¯èƒ½å¤„于 Unicode 范围内。

+

该å˜é‡å¯ç”¨æ¥ç¡®å®šæŸä¸ªè„šæœ¬æ˜¯å¦åœ¨æ­£ç¡®ç‰ˆæœ¬èŒƒå›´å†…çš„ Perl 解释器上è¿è¡Œã€‚(助记:用 ^V 进行版本控制。) 例如:

+
    warn "No \"our\" declarations!\n" if $^V and $^V lt v5.6.0;
+

可以用 sprintf() çš„ "%vd" 转æ¢å°† $^V å˜æˆç­‰ä»·çš„字符串表达形å¼ï¼š

+
    printf "version is v%vd\n", $^V;  # Perl's version
+

关于在è¿è¡Œçš„ Perl 解释器过于å¤è€æ—¶äº§ç”Ÿå¤±è´¥çš„方便方法,请å‚è§ use VERSION å’Œ require VERSION 的文档。

+

较è€çš„ Perl ç‰ˆæœ¬è¡¨ç¤ºæ³•è¯·è§ $]

+
+
$WARNING
+
+
$^W
+

警告开关的当å‰å€¼ï¼Œå½“使用 -w æ—¶åˆå§‹åŒ–为真,å¦åˆ™ä¸ºå‡ï¼Œä¸è¿‡å¯ä»¥ç›´æŽ¥ä¿®æ”¹ã€‚ (åŠ©è®°ï¼šåŒ -w 开关相关。) å¦è§ warnings

+
${^WARNING_BITS}
+

当å‰ç”± use warnings 指示符打开的警告检查集åˆã€‚更多细节å‚è§ warnings çš„ 文档。

+
$EXECUTABLE_NAME
+
+
$^X
+
+

是ç”¨äºŽæ‰§è¡Œå½“å‰ Perl 副本的å称,æ¥è‡ª C çš„ argv[0]

+

根æ®ä¸»æœºæ“作系统,$^X 的值å¯èƒ½æ˜¯ perl 程åºæ–‡ä»¶çš„一个相对或ç»å¯¹è·¯å¾„å〠或者是用于调用 perl 而ä¸æ˜¯ perl 程åºæ–‡ä»¶è·¯å¾„å的字符串。å¦å¤–,多数 æ“作系统å…许调用ä¸åœ¨ PATH 环境å˜é‡ä¸­çš„程åºï¼Œå› æ­¤å¹¶ä¸ä¿è¯ $^X 的值一定 在 PATH 中。对 VMS æ¥è¯´ï¼Œè¯¥å€¼å¯èƒ½åŒ…å«ä¸€ä¸ªç‰ˆæœ¬å·ã€‚

+

通常å¯ä»¥ç”¨ $^X 的值å†æ¬¡äº§ç”Ÿå’Œå½“å‰è¿è¡Œçš„ perl 相åŒçš„一个独立副本,例如,

+
  @first_run = `$^X -le "print int rand 100 for 1..100"`;
+

但考虑到并ä¸æ˜¯æ‰€æœ‰çš„æ“作系统都支æŒåˆ†å‰æˆ–æ•èŽ·å‘½ä»¤çš„输出,这æ¡å¤æ‚çš„è¯­å¥ ä¹Ÿè®¸ä¸å¯ç§»æ¤ã€‚

+

将 $^X 的值用作一个文件的路径å并ä¸å®‰å…¨ï¼Œå› ä¸ºæŸäº›ä¸ºå¯æ‰§è¡Œæ–‡ä»¶ä½¿ç”¨å¼ºåˆ¶åŽç¼€ çš„æ“作系统在调用一个命令时并ä¸éœ€è¦ä½¿ç”¨è¯¥åŽç¼€ã€‚è¦å°† $^X 的值还原为路径å, å¯ä»¥ç”¨å¦‚下语å¥ï¼š

+
  # Build up a set of file names (not command names).
+  use Config;
+  $this_perl = $^X;
+  if ($^O ne 'VMS')
+     {$this_perl .= $Config{_exe}
+          unless $this_perl =~ m/$Config{_exe}$/i;}
+

由于许多æ“作系统å…许任何对 Perl 程åºæ–‡ä»¶å…·æœ‰è¯»æƒé™çš„用户å¤åˆ¶è¯¥æ–‡ä»¶ã€å¯¹å…¶æ‰“ è¡¥ä¸å¹¶æ‰§è¡Œä¹‹ï¼Œå¯¹å®‰å…¨æ•æ„Ÿçš„ Perl 程åºå‘˜åº”注æ„调用 perl 的安装副本而ä¸æ˜¯ $^X 引用的副本。下é¢çš„语å¥å¯ä»¥å®Œæˆè¯¥ç›®çš„,产生一个å¯ä»¥ä½œä¸ºå‘½ä»¤æˆ–当作文件引用的 路径å。

+
  use Config;
+  $secure_perl_path = $Config{perlpath};
+  if ($^O ne 'VMS')
+     {$secure_perl_path .= $Config{_exe}
+          unless $secure_perl_path =~ m/$Config{_exe}$/i;}
+
+
ARGV
+

@ARGV 里的命令行文件å进行迭代的特殊文件å¥æŸ„。通常写为角æ“作符 <> 中的空文件å¥æŸ„。注æ„ç›®å‰ ARGV 仅在 <> æ“作符内具有这一 特殊效果;在其他ä½ç½®ä¸Šå®ƒåªæ˜¯ä¸€ä¸ªå¯¹åº”于 <> 打开的最åŽä¸€ä¸ªæ–‡ä»¶çš„普通 文件å¥æŸ„。特别地,将 \*ARGV 作为å‚数传递给期望一个文件å¥æŸ„的函数时, 函数ä¸ä¸€å®šèƒ½è‡ªåŠ¨è¯»å– @ARGV 中所有文件的内容。

+
$ARGV
+

当è¯»å– <> 时包å«å½“å‰æ–‡ä»¶å。

+
@ARGV
+

数组 @ARGV å«æœ‰è„šæœ¬çš„命令行å‚数。$#ARGV 通常是å‚æ•°æ•°é‡å‡ 1,因为 $ARGV[0] 是第一个å‚数,而不是程åºæœ¬èº«çš„命令å称。命令åç§°è¯·è§ $0

+
ARGVOUT
+

-i 进行原地编辑处ç†æ—¶ï¼Œè¿™æ˜¯æŒ‡å‘当å‰æ‰“开的输出文件的特殊文件å¥æŸ„。当你需è¦è¿›è¡Œ 大é‡æ’å…¥æ“作而ä¸æƒ³ä¸€ç›´ä¿®æ”¹ $_ 时,该å¥æŸ„相当有用。关于 -i 开关请å‚考 perlrun

+
@F
+

当打开自动分割模å¼æ—¶ï¼Œæ•°ç»„ @F 包å«è¯»å…¥çš„一行所产生的域内容。关于 -a 开关请å‚考 perlrun。该数组是包内的特殊å˜é‡ï¼Œå½“è¿è¡Œåœ¨ strict 'vars' 模å¼ä¸‹ä¸”ä¸å¤„于 main 包 内时,必须对其进行声明或给出完整的包å。

+
@INC
+
+

数组 @INC 包å«ä¸€ä¸ªè·¯å¾„列表,do EXPRrequire å’Œ use 结构都会在该列表中查找自己 所需的库文件。它的åˆå§‹å€¼ç”±æ‰€æœ‰ -I 命令行开关的å‚æ•°ã€é»˜è®¤ Perl 库目录(如 /usr/local/lib/perl) 和代表当å‰ç›®å½•çš„“.â€ä¾æ¬¡ç»„åˆè€Œæˆã€‚(当使用 -T 或 -t å¼€å¯ æ±¡æŸ“æ£€æŸ¥å¼€å¯æ—¶åˆ™ä¸ä¼šæŠŠâ€œ.â€é™„加在åŽé¢ã€‚) 若需è¦åœ¨è¿è¡Œæ—¶ä¿®æ”¹è¯¥å˜é‡ï¼Œä½ åº”该使用 use lib 指示符,以便能正确载入平å°ç›¸å…³çš„库:

+
    use lib '/mypath/libdir/';
+    use SomeMod;
+

你还å¯ä»¥ç›´æŽ¥åœ¨ @INC 中放入 Perl 代ç ï¼Œä»¥è¾¾åˆ°åœ¨æ–‡ä»¶åŒ…å«ç³»ç»Ÿä¸­æ’入拦截点的目的。这些拦截点 å¯ä»¥æ˜¯å‡½æ•°å¼•ç”¨ã€æ•°ç»„引用或 bless 过的对象。细节请å‚考 "require" in perlfunc

+
+
@_
+

在æŸä¸ªå‡½æ•°å†…,数组 @_ 包å«ä¼ é€’给该函数的所有å‚数。å‚è§ perlsub

+
%INC
+

散列表 %INC å«æœ‰è‹¥å¹²é¡¹ï¼Œæ¯ä¸€é¡¹éƒ½ä»£è¡¨ç”± dorequire å’Œ use è¿ç®—符包å«è¿›æ¥çš„一个 文件。散列键是包å«å¤„给定的文件å(模å—å已转æ¢ä¸ºè·¯å¾„å),散列值为找到该文件的ä½ç½®ã€‚ require è¿ç®—符用这个散列表判断æŸä¸ªç‰¹å®šæ–‡ä»¶æ˜¯å¦å·²ç»è¢«åŒ…å«è¿‡ã€‚

若æŸä¸ªæ–‡ä»¶æ˜¯ç”±æ‹¦æˆªç‚¹(例如一个函数引用,这些拦截点的说明å‚è§ "require" in perlfunc)载入的, 那么默认æ’å…¥ %INC 的是这个拦截点而ä¸æ˜¯æ–‡ä»¶å。但è¦æ³¨æ„的是,拦截点å¯èƒ½å·²ç»è‡ªè¡Œä¿®æ”¹äº† %INC 中的对应项以æä¾›æŸäº›ç‰¹åˆ«ä¿¡æ¯ã€‚

+
%ENV
+
+
$ENV{expr}
+

散列表 %ENV å«æœ‰å½“å‰çš„环境。对 ENV 设置值会改å˜åŽç»­ fork() 出æ¥çš„所有å­è¿›ç¨‹çš„环境。

+
%SIG
+
+
$SIG{expr}
+
+

散列表 %SIG 包å«ä¿¡å·å¯¹åº”的处ç†å™¨ã€‚例如:

+
    sub handler {       # 第一个å‚数是信å·å称
+        my($sig) = @_;
+        print "Caught a SIG$sig--shutting down\n";
+        close(LOG);
+        exit(0);
+    }
+
+    $SIG{'INT'}  = \&handler;
+    $SIG{'QUIT'} = \&handler;
+    ...
+    $SIG{'INT'}  = 'DEFAULT';   # æ¢å¤é»˜è®¤è¡Œä¸º
+    $SIG{'QUIT'} = 'IGNORE';    # 忽略 SIGQUIT
+

设置为 'IGNORE' 值通常具有忽略该信å·çš„效果,除了 CHLD ä¿¡å·ä»¥å¤–。对于这一特殊情况 çš„è¯¦ç»†è¯´æ˜Žè¯·è§ perlipc

+

下é¢æ˜¯å…¶ä»–一些例å­ï¼š

+
    $SIG{"PIPE"} = "Plumber";   # å‡å®šä¸º main::Plumber (ä¸æŽ¨è)
+    $SIG{"PIPE"} = \&Plumber;   # 挺好;å‡å®šä¸ºå½“å‰çš„ Plumber
+    $SIG{"PIPE"} = *Plumber;    # 有点儿深奥
+    $SIG{"PIPE"} = Plumber();   # å•Šï¼Plumber() 返回的是什么?
+

请ç¡®ä¿æ²¡æœ‰ä½¿ç”¨è£¸å­—作为一个信å·å¤„ç†å™¨çš„å字,å…得产生无æ„中的调用。

+

如果系统有 sigaction() 函数,就用它æ¥å®‰è£…ä¿¡å·å¤„ç†å™¨ã€‚è¿™æ„味ç€ä½ èƒ½å¾—到å¯é çš„ä¿¡å·å¤„ç†æ–¹å¼ã€‚

+

默认的信å·æŠ•é€’策略在 Perl 5.8.0 中从立å³å‘é€(也å³â€œä¸å®‰å…¨â€)改为了延迟å‘é€ï¼Œå³â€œå®‰å…¨ä¿¡å·â€ 。更多信æ¯è¯·è§ perlipc

+

用 %SIG 散列表也å¯ä»¥è®¾ç½®ç‰¹å®šçš„内部拦截点。在å³å°†æ‰“å°ä¸€æ¡è­¦å‘Šä¿¡æ¯æ—¶ï¼Œç”± $SIG{__WARN__} 指定的例程会被调用。警告信æ¯ä½œä¸ºç¬¬ä¸€ä¸ªå‚数被传递给该例程。__WARN__ 拦截点的存在会消除通常 è¦æ‰“å°åˆ° STDERR 上的警告。你å¯ä»¥åˆ©ç”¨è¿™ä¸€ç‚¹å°†è­¦å‘Šä¿å­˜åˆ°å˜é‡é‡Œï¼Œæˆ–者åƒè¿™æ ·å°†è­¦å‘Šè½¬å˜ä¸ºè‡´å‘½é”™è¯¯ï¼š

+
    local $SIG{__WARN__} = sub { die $_[0] };
+    eval $proggie;
+

当å³å°†æŠ›å‡ºä¸€ä¸ªè‡´å‘½å¼‚常时,由 $SIG{__DIE__} 指定的例程会被调用。错误信æ¯ä½œä¸ºç¬¬ä¸€ä¸ªå‚数被 传递给该例程。当 __DIE__ 拦截例程返回åŽï¼Œå¼‚常处ç†ä¼šåƒæ‹¦æˆªç‚¹ä¸å­˜åœ¨ä¸€æ ·ç»§ç»­è¿›è¡Œï¼Œé™¤éžæ‹¦æˆªä¾‹ç¨‹ 本身通过 goto、循环退出或 die() çš„æ–¹å¼ç»“æŸã€‚__DIE__ 处ç†å™¨åœ¨è°ƒç”¨è¿‡ç¨‹ä¸­è¢«æ˜¾å¼å…³é—­ï¼Œå› æ­¤ ä½ å¯ä»¥åœ¨ __DIE__ 处ç†å™¨ä¸­ç»§ç»­ die。__WARN__ 也具有类似行为。

+

由于一个实现的å°é—®é¢˜ï¼Œ$SIG{__DIE__} 拦截点å³ä½¿åœ¨ eval() 内也会被调用。请ä¸è¦åˆ©ç”¨è¿™ä¸€ç‚¹å¤ç›– $@ 中挂起的异常或莫å其妙地é‡è½½ CORE::GLOBAL::die()。这一奇特行为在将æ¥åº”该会被修正为åªåœ¨ 程åºå³å°†é€€å‡ºæ—¶è°ƒç”¨ $SIG{__DIE__},这也是最åˆçš„目的。ä¸åº”采用任何其他形å¼çš„用法。

+

__DIE__/__WARN__ 处ç†å™¨åœ¨ä¸€ç§æƒ…况下是很特殊的: 它们å¯èƒ½ä¼šåœ¨æ±‡æŠ¥è§£æžå™¨å‘现的(å¯èƒ½)错误时被调用。在这ç§æƒ…况下解æžå™¨å¯èƒ½å¤„于ä¸ä¸€è‡´çš„状æ€ï¼Œä»»ä½•ä»Ž 这类处ç†å™¨ä¸­ eval Perl 代ç çš„å°è¯•éƒ½å¯èƒ½å¯¼è‡´æ®µé”™è¯¯ã€‚è¿™æ„味ç€å¤„ç†è§£æž Perl 时产生的警告或错误时应 æžåº¦å°å¿ƒï¼Œåƒè¿™æ ·ï¼š

+
    require Carp if defined $^S;
+    Carp::confess("Something wrong") if defined &Carp::confess;
+    die "Something wrong, but could not load Carp to give backtrace...
+         To see backtrace try starting Perl with -MCarp switch";
+

这里的第一行åªæœ‰åœ¨è°ƒç”¨å¤„ç†å™¨çš„对象不是解æžå™¨æ—¶æ‰ä¼šæ‰§è¡Œè½½å…¥æ“作。第二行åªæœ‰åœ¨ Carp å¯ç”¨æ—¶æ‰æ‰“å° å‡ºå›žæº¯ä¿¡æ¯å¹¶é€€å‡ºç¨‹åºã€‚第三行则仅在 Carp ä¸å¯ç”¨æ—¶æ‰ä¼šè¿è¡Œã€‚

+

额外信æ¯è¯·è§ "die" in perlfunc"warn" in perlfunc"eval" in perlfunc å’Œ warnings

+
+
+

错误指示器

+

变é‡ $@$!$^E å’Œ $? å«æœ‰å…³äºŽä¸åŒç±»åž‹é”™è¯¯æ¡ä»¶çš„ä¿¡æ¯ï¼Œè¿™äº›é”™è¯¯å¯èƒ½åœ¨æ‰§è¡Œä¸€ä¸ª Perl 程åºæ—¶äº§ç”Ÿã€‚这些å˜é‡æŒ‰ç…§åˆ° Perl 进程和错误报告å­ç³»ç»Ÿçš„“è·ç¦»â€è¿œè¿‘排列顺åºï¼Œå®ƒä»¬åˆ†åˆ«å¯¹åº”ç”± Perl 解释器ã€C 库ã€æ“作系统和外部程åºæ£€æµ‹åˆ°çš„错误。

+

为了展示这些å˜é‡ä¹‹é—´çš„区别,请考虑以下这个使用了å•å¼•å·å¼•èµ·å­—符串的 Perl 表达å¼ï¼š

+
    eval q{
+        open my $pipe, "/cdrom/install |" or die $!;
+        my @res = <$pipe>;
+        close $pipe or die "bad pipe: $?, $!";
+    };
+

当è¿™æ¡è¯­å¥æ‰§è¡Œä¹‹åŽï¼Œ4 个å˜é‡éƒ½æœ‰å¯èƒ½è¢«è®¾ç½®ã€‚

+

在éœ€è¦ eval 的字符串没有通过编译(è‹¥ open 或 close 导入的原型错误则å¯èƒ½å‘生)或者 Perl 代ç åœ¨æ‰§è¡Œè¿‡ç¨‹ä¸­ die() 掉,则 $@ å˜é‡ä¼šè¢«è®¾ç½®ã€‚这些情况下 $@ 的值是编译错误信æ¯æˆ– die çš„ å‚æ•°(å…¶ä¸­ä¼šå†…æ’ $! å’Œ $?)。(å¦è§ Fatal。)

+

上é¢çš„ eval() 表达å¼æ‰§è¡ŒåŽï¼Œopen()ã€<PIPE> å’Œ close 被翻译æˆå¯¹ C è¿è¡Œåº“的调用,继而 进入æ“作系统内核。若其中æŸä¸ªè°ƒç”¨å¤±è´¥ï¼Œåˆ™ $! 会设置为 C 库的 errno 值。

+

在å°‘æ•°æ“作系统下,$^E å¯èƒ½å«æœ‰æ›´è¯¦ç»†çš„错误指示,例如“CDROM 仓门没有关闭â€ã€‚ä¸æ”¯æŒæ‰©å±•é”™è¯¯ ä¿¡æ¯çš„系统åªæ˜¯å°† $^E 设置为和 $! 一样的值。

+

最åŽï¼Œ$? åœ¨å¤–éƒ¨ç¨‹åº /cdrom/install å¤±è´¥æ—¶è®¾ç½®ä¸ºéž 0 值。高 8 ä½å映出该程åºé‡åˆ°çš„特定错误 æ¡ä»¶(程åºçš„ exit() 值),低 8 ä½å映失败方å¼ï¼Œä¾‹å¦‚ä¿¡å·è‡´æ­»æˆ–核心转储,细节å‚è§ wait(2)。对比 仅在检测到错误æ¡ä»¶æ—¶æ‰è®¾ç½®çš„ $! å’Œ $^E,å˜é‡ $? 在æ¯ä¸ª wait æˆ–ç®¡é“ close 时都会 设置并冲掉旧值。这一行为更接近 $@,åŽè€…在æ¯æ¬¡ eval() åŽæ€»æ˜¯åœ¨å¤±è´¥æ—¶è®¾ç½®å¹¶åœ¨æˆåŠŸæ—¶æ¸…除。

+

更多细节请分别å‚è§ $@$!$^E å’Œ $? å„自的说明。

+

关于å˜é‡å语法的技术事项

+

Perl 中的å˜é‡åå¯ä»¥æœ‰å¤šç§æ ¼å¼ã€‚通常,它们è¦ä»¥ä¸‹åˆ’线或字æ¯å¼€å¤´ï¼Œè¿™ç§æƒ…况下å˜é‡åå¯ä»¥ä»»æ„é•¿(但有 251 个字符的内部é™åˆ¶)且å¯åŒ…å«å­—æ¯ã€æ•°å­—ã€ä¸‹åˆ’线或特殊åºåˆ— :: å’Œ '。最åŽä¸€ä¸ª :: 或 ' 之å‰çš„ 部分被当作包é™å®šç¬¦;å‚è§ perlmod

+

Perl å˜é‡å也å¯ä»¥æ˜¯ä¸€ä¸²æ•°å­—ã€å•ä¸ªæ ‡ç‚¹æˆ–控制符。这些å字都被 Perl ä¿ç•™ç”¨ä½œç‰¹æ®Šç”¨é€”;例如,全数字的 å字用æ¥åœ¨æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…之åŽä¿å­˜åå‘引用æ•èŽ·çš„æ•°æ®ã€‚Perl 对å•ä¸ªæŽ§åˆ¶ç¬¦çš„å字具有一套特殊语法:它将 ^X (脱字符åŽè·Ÿ X) ç†è§£ä¸º Ctrl-X 字符。例如,记法 $^W (美元符 脱字符 W) 是一个åå­— 为å•ä¸ªå­—符 Ctrl-W çš„æ ‡é‡å˜é‡ã€‚è¿™è¦æ¯”在程åºé‡Œé”®å…¥ä¸€ä¸ªå­—é¢ä¸Šçš„ Ctrl-W 好一些。

+

最åŽï¼Œåœ¨ Perl 5.6 中引入了一个新特性,Perl å˜é‡åå¯ä»¥æ˜¯ä»¥æŽ§åˆ¶ç¬¦(更进一步,也å¯ä»¥æ˜¯è„±å­—符)å¼€å¤´çš„å­—æ¯ æ•°å­—å­—ç¬¦ä¸²ã€‚è¿™äº›å˜é‡å¿…é¡»å†™æˆ ${^Foo} çš„å½¢å¼ï¼›å¤§æ‹¬å·æ˜¯å¿…需的。${^Foo} 代表了一个å字是 Ctrl-F åŽè·Ÿä¸¤ä¸ª o çš„æ ‡é‡ã€‚这些å˜é‡è¢« Perl ä¿ç•™ä½œå°†æ¥çš„特殊用途,但以 ^_ (Ctrl-下划线或 脱字符-下划线)开头的那些除外。以 ^_ 开头的åå­—å°†ä¸ä¼šåœ¨ Perl 的未æ¥ç‰ˆæœ¬ä¸­äº§ç”Ÿä»»ä½•ç‰¹æ®Šå«ä¹‰ï¼›å› è€Œ å¯ä»¥åœ¨ç¨‹åºä¸­å®‰å…¨ä½¿ç”¨è¿™ç±»å字。但 $^_ 本身保留的。

+

以æ•°å­—ã€æŽ§åˆ¶ç¬¦æˆ–标点字符开头的 Perl 标识符ä¸å— package 声明的影å“,它们始终被强制在 main 包里; å¦å¤–它们也ä¸å— strict 'vars' 错误的约æŸã€‚其他一å°éƒ¨åˆ†å字也具有åŒæ ·çš„è±å…æƒï¼š

+
        ENV             STDIN
+        INC             STDOUT
+        ARGV            STDERR
+        ARGVOUT         _
+        SIG
+

特别地,ä¸ç®¡å½“å‰ä½œç”¨åŸŸä¸­çš„ package 声明如何,新形å¼çš„特殊å˜é‡ ${^_XYZ} 总是被放置在 main 包里。

+

BUGS

+

由于 Perl 实现时一个ä¸å¹¸çš„事故,use English 会使程åºä¸­æ‰€æœ‰æ­£åˆ™è¡¨è¾¾å¼åŒ¹é…产生显著的效率é™ä½Žï¼Œä¸ç®¡å®ƒä»¬ 是å¦å‡ºçŽ°åœ¨ use English 的作用域里。因此,强烈ä¸æŽ¨è在库里使用 use English。更多信æ¯è¯·å‚è§ CPAN 上的 Devel::SawAmpersand 模å—文档 ( http://www.cpan.org/modules/by-module/Devel/ )。

+

在异常处ç†å™¨ä¸­ä¸åº”该考虑 $^S$SIG{__DIE__} 的当å‰å®žçŽ°ä»¤äººä¼¤å¿ƒï¼Œå¾ˆéš¾ç”¨å®ƒè·Ÿè¸ªé”™è¯¯ã€‚请é¿å…使用它并 用 END{} 或 CORE::GLOBAL::die é‡è½½æ¥ä»£æ›¿ä¹‹ã€‚

+

TRANSLATORS

+

ChaosLawful

+ + diff --git a/POD/CN_html/perlxstut.html b/POD/CN_html/perlxstut.html new file mode 100644 index 0000000..d376ec0 --- /dev/null +++ b/POD/CN_html/perlxstut.html @@ -0,0 +1,624 @@ + + + + perlxstut + + + + +

NAME

+

perlxstut - 写 XSUBs 指å—

+

DESCRIPTION

+

这个指å—让你明白创建一个 Perl 扩展的步骤。我å‡å®šä½ å·²ç»è¯»è¿‡äº† perlgutsperlapi å’Œ perlxs

+

我将以一个éžå¸¸ç®€å•çš„例å­å¼€å§‹ï¼Œç„¶åŽåŠ å…¥æ–°çš„例å­å’Œç‰©æ€§ï¼Œä½¿å®ƒé€æ¸å˜å¾—å¤æ‚。 为了让你更容易开始,一些概念è¦åˆ°åŽé¢æ‰å®Œå…¨å‘你解释。

+

这个指å—是从 Unix 的角度写的。其它æ“作系统å¯èƒ½ä¼šä¸ä¸€æ ·ï¼Œæˆ‘会尽我所知的 把它列出æ¥ã€‚如果你å‘现我é—æ¼çš„地方,请告诉我。

+

SPECIAL NOTES

+

make 程åº

+

我å‡å®š Perl é…置的 make 程åºç§°ä¸º make。在以下的例å­ä¸­ï¼Œä½ éœ€è¦æŠŠ “makeâ€æ›¿æ¢ä¸ºä½ çš„ Perl é…置使用的 make 程åºã€‚è¿è¡Œ perl -V:make 将知 é“ä½ çš„ make 程åºæ˜¯ä»€ä¹ˆã€‚

+

版本说明

+

当写一个通常用途的 Perl 扩展,你应该è¦è€ƒè™‘到这个扩展å¯èƒ½è¢«ç”¨äºŽä¸Žä½ æœºå™¨ 上版本ä¸åŒçš„ Perl。当你读这篇文章时,你的 Perl 的版本å¯èƒ½æ˜¯ 5.005 或 者更高。但是使用你的扩展的用户å´å¾ˆå¯èƒ½åªæœ‰æ¯”è¿™å¤è€çš„版本。

+

要了解å„ç§å¯èƒ½è€ƒè™‘的兼容性问题,或者应付你机器上的 Perl ç‰ˆæœ¬æ¯”è¿™ç¯‡æ–‡ç« æ›´å¤ è€çš„特殊情况,å‚考“消除这些例å­ä¸­çš„问题â€è¿™ä¸€èŠ‚。

+

如果你的扩展使用了一些旧版本的 Perl ä¸å…·æœ‰çš„特性,你的用户很希望你能够尽 æ—©æ醒他。你å¯ä»¥æŠŠè¿™äº›ä¿¡æ¯å†™åˆ° README 文件中。但是现在扩展的安装通 常都是由 CPAN.pm 或者其它工具自动完æˆäº†ã€‚

+

在基于 MakeMaker 的安装中,Makefile.PL æ供了第一个进行版本检查的机 会。你å¯ä»¥åœ¨ Makefile.PL 文件中åƒè¿™æ ·å†™ï¼š

+
    eval { require 5.007 }
+        or die <<EOD;
+    ############
+    ### This module uses frobnication framework which is not available before
+    ### version 5.007 of Perl.  Upgrade your Perl before installing Kara::Mba.
+    ############
+    EOD
+

动æ€å¯¼å…¥ä¸Žé™æ€å¯¼å…¥

+

通常会认为如果系统ä¸èƒ½åŠ¨æ€çš„导入库的è¯ï¼Œå°±æ— æ³•åˆ›å»º XSUBs。其实这是错误。 你是可以创建的,但是你必须把 XSUBs å’Œ Perl 的其它部分链接起æ¥ï¼Œåˆ›å»º 一个新的å¯æ‰§è¡Œçš„程åºã€‚这与 Perl 4 的情形很类似。

+

这个指å—ä»ç„¶å¯¹è¿™æ ·çš„系统ä»ç„¶èƒ½å¤Ÿé€‚用。XSUB 的创建机制将检查系统类型, 如果å¯ä»¥åŠ¨æ€å¯¼å…¥ï¼Œå°±åˆ›å»ºä¸€ä¸ªåŠ¨æ€å¯¼å…¥çš„库,å¦åˆ™åˆ›å»ºä¸€ä¸ªé™æ€åº“和一个与这 个é™æ€åº“链接的å¯æ‰§è¡Œç¨‹åºã€‚

+

在以下所有的例å­ä¸­ï¼Œå¦‚果你希望在å¯ä»¥åŠ¨æ€å¯¼å…¥åº“的系统上创建一个é™æ€é“¾æŽ¥ çš„å¯æ‰§è¡Œç¨‹åºï¼Œä½ å¯ä»¥ç”¨â€œmake perl”命令而ä¸æ˜¯æ²¡æœ‰å‚数的“make”。

+

如果你创建一个这样的é™æ€é“¾æŽ¥çš„å¯æ‰§è¡Œç¨‹åºï¼Œé‚£ä½ åº”该用“make test_static”而ä¸æ˜¯â€œmake test”。在ä¸èƒ½åˆ›å»ºåŠ¨æ€å¯¼å…¥åº“的系统上,就用 “make test”就够了。

+

TUTORIAL

+

好了,现在让我们开始å§ï¼

+

例å­ 1

+

我们的第一个扩展将是éžå¸¸çš„简å•ã€‚当我们调用这个扩展的函数时,它将输出那 个有åçš„å¥å­ç„¶åŽè¿”回。

+

运行“h2xs -A -n Mytest”。这将创建一个å为 Mytest 的目录。如果当å‰ç›® å½•ä¸‹æœ‰ä¸€ä¸ªå« ext/ 的目录,å¯èƒ½åœ¨è¿™ä¸ªç›®å½•ä¸‹åˆ›å»ºã€‚在 Mytest 目录中将创建 几个文件,包括 MANIFEST, Makefile.PL, Mytest.pm, Mytest.xs, test.pl å’Œ Changes。

+

MANIFEST 文件内包å«æ‰€æœ‰åˆšæ‰åœ¨ Mytest 目录下创建的文件å。

+

Makefile.PL 文件应该是这样的:

+
        use ExtUtils::MakeMaker;
+        # See lib/ExtUtils/MakeMaker.pm for details of how to influence
+        # the contents of the Makefile that is written.
+        WriteMakefile(
+            NAME         => 'Mytest',
+            VERSION_FROM => 'Mytest.pm', # finds $VERSION
+            LIBS         => [''],   # e.g., '-lm'
+            DEFINE       => '',     # e.g., '-DHAVE_SOMETHING'
+            INC          => '',     # e.g., '-I/usr/include/other'
+        );
+

Mytest.pm 文件应该åƒè¿™æ ·ï¼š

+
        package Mytest;
+
+        use strict;
+        use warnings;
+
+        require Exporter;
+        require DynaLoader;
+
+        our @ISA = qw(Exporter DynaLoader);
+        # Items to export into callers namespace by default. Note: do not export
+        # names by default without a very good reason. Use EXPORT_OK instead.
+        # Do not simply export all your public functions/methods/constants.
+        our @EXPORT = qw(
+
+        );
+        our $VERSION = '0.01';
+
+        bootstrap Mytest $VERSION;
+
+        # Preloaded methods go here.
+
+        # Autoload methods go after __END__, and are processed by the autosplit program.
+
+        1;
+        __END__
+        # Below is the stub of documentation for your module. You better edit it!
+

其它的 .pm 文件是扩展的文档代ç æ ·ä¾‹ã€‚

+

最åŽï¼ŒMytest.xs 文件应该是这样的:

+
        #include "EXTERN.h"
+        #include "perl.h"
+        #include "XSUB.h"
+
+        MODULE = Mytest         PACKAGE = Mytest
+

在这个文件的最åŽåŠ ä¸Šè¿™å‡ è¡Œï¼š

+
        void
+        hello()
+            CODE:
+                printf("Hello, world!\n");
+

以“CODE:â€å¼€å¤´çš„那一行ä¸ç¼©è¿›ä¹Ÿæ²¡æœ‰å…³ç³»ã€‚但是为了å¯è¯»æ€§ï¼Œè¿˜æ˜¯å»ºè®®ä½ ç¼©è¿› 这一行,接下æ¥çš„几行应当å†ç¼©è¿›ä¸€å±‚。

+

现在è¿è¡Œâ€œperl Makefile.PL”。这将创建一个 make 程åºéœ€è¦çš„真正的 Makefile。它的输出应该是这样的:

+
        % perl Makefile.PL
+        Checking if your kit is complete...
+        Looks good
+        Writing Makefile for Mytest
+        %
+

现在,è¿è¡Œ make 将产生这样的输出(为了清楚一些,过长的输出行被缩短了, 有几行被çœç•¥äº†ï¼‰ï¼š

+
        % make
+        umask 0 && cp Mytest.pm ./blib/Mytest.pm
+        perl xsubpp -typemap typemap Mytest.xs >Mytest.tc && mv Mytest.tc Mytest.c
+        Please specify prototyping behavior for Mytest.xs (see perlxs manual)
+        cc -c Mytest.c
+        Running Mkbootstrap for Mytest ()
+        chmod 644 Mytest.bs
+        LD_RUN_PATH="" ld -o ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl -b Mytest.o
+        chmod 755 ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl
+        cp Mytest.bs ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs
+        chmod 644 ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs
+        Manifying ./blib/man3/Mytest.3
+        %
+

你å¯ä»¥å¿½ç•¥äº†â€œprototyping behaviorâ€ï¼Œåœ¨perlxs的“The PROTOTYPES: Keywordâ€ä¸€èŠ‚中将说明这一点。

+

如果你在 Win32 系统,由于与 C 库函数的 linker 错误导致创建过程中止,请 检查你的 Perl 是å¦é…置为使用 PerlCRT(è¿è¡Œ perl -V:libc 将告诉你答 案)。如果 Perl 是é…置为使用 PerlCRT,你看看 PerlCRT.lib 是å¦å¤åˆ¶åˆ° msvcrt.lib 相åŒçš„目录下了。必须在相åŒçš„ä½ç½®ï¼Œç¼–译器æ‰èƒ½æ‰¾åˆ°å®ƒã€‚ msvcrt.lib 通常在 Visual C 编译器的 lib 目录(例如 C:/DevStudio/VC/lib)。

+

Perl 有它自己独特而简å•çš„æ–¹å¼æ¥å†™æµ‹è¯•è„šæœ¬ã€‚但是åªå¯¹äºŽè¿™ä¸ªä¾‹å­ï¼Œæˆ‘们自 己创建测试脚本。创建一个这样å为的 hello 的文件:

+
        #! /opt/perl5/bin/perl
+
+        use ExtUtils::testlib;
+
+        use Mytest;
+
+        Mytest::hello();
+

现在让这个脚本å¯æ‰§è¡Œï¼ˆchmod +x hello),è¿è¡Œè„šæœ¬ï¼Œå°±åº”该å¯ä»¥çœ‹åˆ°è¿™ 样的输出:

+
        % ./hello
+        Hello, world!
+        %
+

例å­ 2

+

现在加入我们扩展——一个的函数,它接收一个整数为å‚数,如果是å¶æ•°å°±è¿”回 0,å¦åˆ™è¿”回1。

+

在 Mytest.xs 的末尾加入:

+
        int
+        is_even(input)
+                int     input
+            CODE:
+                RETVAL = (input % 2 == 0);
+            OUTPUT:
+                RETVAL
+

同样,以“int input”开头的行ä¸éœ€è¦ç¼©è¿›ï¼Œä½†æ˜¯ç¼©è¿›ä½¿å®ƒæ›´å¥½è¯»ã€‚在这一行 末尾å¯ä»¥åŠ ä¸Šä¸€ä¸ªåˆ†å·ã€‚在“int”和“input”之间å¯ä»¥æœ‰ä»»æ„的空格。

+

现在é‡æ–°è¿è¡Œ make æ¥åˆ›å»ºæ–°çš„库。

+

重å¤å‰é¢ç›¸åŒçš„步骤,创建一个 Makefile 然åŽè¿è¡Œ make。

+

为了测试我们的扩展,让我们æ¥çœ‹çœ‹ test.pl 这个文件。这个文件照抄了 Perl 自己的测试结构。通过这个测试脚本,进行一系列的测试æ¥ç¡®å®šæ‰©å±•çš„功能:如 果测试是正确的输出“okâ€ï¼Œå¦åˆ™è¾“出“not okâ€ã€‚修改 BEGIN å—中的 print è¯­å¥ æ¥è¾“出“1..4â€ï¼Œç„¶åŽåœ¨æ–‡ä»¶æœ«å°¾åŠ å…¥è¿™äº›ä»£ç ï¼š

+
        print &Mytest::is_even(0) == 1 ? "ok 2" : "not ok 2", "\n";
+        print &Mytest::is_even(1) == 0 ? "ok 3" : "not ok 3", "\n";
+        print &Mytest::is_even(2) == 1 ? "ok 4" : "not ok 4", "\n";
+

通过命令“make test”æ¥è°ƒç”¨æµ‹è¯•è„šæœ¬ã€‚你将看到这样的输出:

+
        % make test
+        PERL_DL_NONLAZY=1 /opt/perl5.004/bin/perl (lots of -I arguments) test.pl
+        1..4
+        ok 1
+        ok 2
+        ok 3
+        ok 4
+        %
+

我们åšäº†äº›ä»€ä¹ˆå‘¢ï¼Ÿ

+

h2xs 是创建扩展的起点。在接下æ¥çš„例å­ä¸­æˆ‘们将看到å¯ä»¥ç”¨ h2xs æ¥è¯»å–头 文件并产生连接到 C 函数的模æ¿ã€‚

+

h2xs 在扩展所在的目录里创建一系列的文件。Makefile.PL 文件是一个将产生 真正 Makefile 的 perl 脚本。我们将更深入的了解它。

+

.pm å’Œ .xs 文件包å«äº†æ‰©å±•çš„主è¦å†…容。.xs 文件里是构æˆæ‰©å±•çš„ C 函数。.pm 文件告诉 Perl 怎样导入你的扩展。

+

产生 Makefile å’Œè¿è¡Œ make 在当å‰ç›®å½•ä¸‹åˆ›å»ºä¸€ä¸ªå« blib 的目录(æ„æ€æ˜¯ “build libraryâ€ï¼‰ã€‚这个目录将包å«åˆ›å»ºçš„共享库。当我们测试完毕åŽï¼Œå®ƒå°†å®‰è£… 在最终的ä½ç½®ã€‚

+

通过“make test”调用测试脚本的过程中å‘生一些很é‡è¦çš„事。它使用了所有 çš„ -I 选项æ¥è°ƒç”¨ perl 以ä¿è¯ perl 能够找到属于扩展的文件。使用 “make test”对于测试你的扩展是很é‡è¦çš„。如果你试图自己è¿è¡Œæµ‹è¯•è„šæœ¬ï¼Œ 这将产生一个错误。å¦ä¸€ä¸ªä½¿ç”¨â€œmake test”的原因是,如果你在测试一个已 ç»å­˜åœ¨çš„版本å‡çº§çš„模å—,这å¯ä»¥ä¿è¯ä½ æµ‹è¯•çš„是你的新版本,而ä¸æ˜¯åŽŸæ¥é‚£ä¸ªã€‚

+

当 Perl 看到 use extension; 时,它将æœç´¢ä¸€ä¸ªå…·æœ‰ .pm åŽç¼€ã€ä¸Ž use åŽ extension å字相åŒçš„文件。如果找ä¸åˆ°è¿™æ ·çš„文件,Perl 将产生 一个致命错误而终止。默认的æœç´¢è·¯å¾„是在 @INC 数组中。

+

在我们这个例å­ä¸­ï¼ŒMytest.pm 告诉 perl å®ƒå°†éœ€è¦ Exporter å’Œ Dynamic Loader 扩展。它设置 @ISA å’Œ @EXPORT æ•°ç»„ä»¥åŠ $VERSION æ ‡é‡ï¼› 最终它告诉 perl 引导这个模å—。perl 将调用它的动æ€å¯¼å…¥å‡½æ•°ï¼ˆå¦‚果有的è¯ï¼‰å¹¶ 导入共享库。

+

@ISA å’Œ @EXPORT 这两个数组是éžå¸¸é‡è¦çš„。@ISA 数组包å«å°†è¦ç”¨æ¥ æœç´¢å½“å‰åŒ…中ä¸å­˜åœ¨çš„方法(或者函数)的其它包。这对于é¢å‘对象的扩展通常 是å分é‡è¦çš„(我们将在以åŽè°ˆåŠè¿™ä¸ªé—®é¢˜ï¼‰ï¼Œæ‰€ä»¥é€šå¸¸æ˜¯ä¸éœ€è¦ä¿®æ”¹çš„。

+

@EXPORT 数组告诉 Perl 扩展中的哪些å˜é‡å’Œå‡½æ•°å°†æ”¾åˆ°è°ƒç”¨è€…çš„å字空间。 因为你ä¸çŸ¥é“用户是å¦ä½¿ç”¨äº†ä½ çš„å˜é‡å或者函数å,所以有选择的导出是至关 é‡è¦ã€‚没有好的ç†ç”±不è¦默认导出å˜é‡å’Œæ–¹æ³•ã€‚

+

作为一个普é的规则,如果模å—是é¢å‘对象的,就ä¸è¦å¯¼å‡ºä»»ä½•ä¸œè¥¿ã€‚如果åªæ˜¯ 一个方法和å˜é‡çš„集åˆï¼Œä½ å¯ä»¥é€šè¿‡å¦ä¸€ä¸ªç§°ä¸º EXPORT_OK 的数组导出。这 个数组并ä¸è‡ªåŠ¨çš„把å˜é‡å’Œå‡½æ•°å放入å字空间,除éžç”¨æˆ·æœ‰ç‰¹åˆ«éœ€è¦æ‰è¿™æ ·åšã€‚

+

参考 perlmod 得到更多的内容。

+

$VERSION å˜é‡ä¿è¯ .pm 文件和共享库是互相åŒæ­¥çš„。当你改动 .pm 或者 .xs 文件时,这个å˜é‡çš„值也è¦ç›¸åº”的增加。

+

写好测试脚本

+

写一个好的测试脚本的é‡è¦æ€§æ˜¯ä¸å®¹ç½®ç–‘的。你å¯ä»¥ç”¨ Perl 本身使用的 “ok/not okâ€é£Žæ ¼ï¼Œè¿™æ ·æ“作容易而且æ¯ä¸ªæµ‹è¯•çš„输出éžå¸¸æ˜Žç¡®ã€‚当你找到并修 正一个错误时,一定è¦ä¸ºæ­¤å¢žåŠ ä¸€ä¸ªæµ‹è¯•ã€‚

+

通过è¿è¡Œâ€œmake test”,你å¯ä»¥ç¡®ä¿¡ä½ çš„ test.pl è¿è¡Œäº†ï¼Œè€Œä¸”使用的是正确 的版本。如果你有很多的测试,你也许会模仿 Perl 的测试风格:在扩展所在的 目录下创建一个åå«â€œtâ€çš„目录,添加åŽç¼€â€œ.tâ€åˆ°ä½ çš„测试文件。当你è¿è¡Œ “make test”时,所有这些文件都将执行。

+

例å­ 3

+

我们第三个例å­å°†ç”¨ä¸€ä¸ªå‚数作为输入,四èˆäº”入,然åŽå°†参æ•°设置为å–æ•´ åŽçš„值。

+

在 Mytest.xs 末尾加入:

+
        void
+        round(arg)
+                double  arg
+            CODE:
+                if (arg > 0.0) {
+                        arg = floor(arg + 0.5);
+                } else if (arg < 0.0) {
+                        arg = ceil(arg - 0.5);
+                } else {
+                        arg = 0.0;
+                }
+            OUTPUT:
+                arg
+

编辑 Makefile.PL 的相应行,使它æˆä¸ºè¿™æ ·ï¼š

+
        'LIBS'      => ['-lm'],   # e.g., '-lm'
+

产生 Makefile 并è¿è¡Œ make。修改 BEGIN å—æ¥è¾“出“1..9â€ï¼Œç„¶åŽåœ¨ test.pl 中加入:

+
        $i = -1.5; &Mytest::round($i); print $i == -2.0 ? "ok 5" : "not ok 5", "\n";
+        $i = -1.1; &Mytest::round($i); print $i == -1.0 ? "ok 6" : "not ok 6", "\n";
+        $i = 0.0; &Mytest::round($i); print $i == 0.0 ? "ok 7" : "not ok 7", "\n";
+        $i = 0.5; &Mytest::round($i); print $i == 1.0 ? "ok 8" : "not ok 8", "\n";
+        $i = 1.2; &Mytest::round($i); print $i == 1.0 ? "ok 9" : "not ok 9", "\n";
+

运行“make test”åŽåº”该输出这ä¹ä¸ªæµ‹è¯•éƒ½é€šè¿‡ã€‚

+

注æ„到在新的测试中,传递给 round çš„å‚数是一个标é‡ã€‚ä½ å¯èƒ½æƒ³çŸ¥é“如果传递一个 常数或者文字将å‘生什么。在 test.pl 中暂时加入这样一行:

+
        &Mytest::round(3);
+

运行“make test”,应该看到 Perl 由于致命错误而退出。Perl ä¸ä¼šè®©ä½ ä¿® 改一个常数的值ï¼

+

有什么新东西?

+
    +
  • 我们对 Makefile.PL åšäº†ä¸€äº›ä¿®æ”¹ã€‚在这个例å­ä¸­ï¼Œæˆ‘们指定了一个é¢å¤–的库—— math 库 libm 链接到扩展的共享库中。接下æ¥ï¼Œæˆ‘们将介ç»å¦‚果在 XSUBs 中调 用库中的所有函数。
  • +
  • 传递的值没有åšä¸ºå‡½æ•°çš„返回值,而是直接修改这个值。当你看到 round 函数 的返回值类型是“voidâ€ï¼Œä½ å¯èƒ½å·²ç»çŒœåˆ°äº†è¿™ä¸€ç‚¹ã€‚
  • +
+

输入和输出å‚æ•°

+

在声明函数的返回值和函数å之åŽçš„一行你需è¦æŒ‡å®šä¼ é€’ç»™ XSUB çš„å‚数。æ¯ä¸ª 声明传入å‚数的行都以å¯é€‰çš„空白开始,以å¯é€‰çš„分å·ç»“尾。

+

输出å‚数列在æ¯ä¸ªå‡½æ•°çš„结尾,在 OUTPUT: 指令之åŽã€‚使用 RETVAL 则告诉 Perl 你希望这个值将作为这个 XSUB å‡½æ•°çš„è¿”å›žå€¼ã€‚åœ¨ä¾‹å­ 3 中,我们想è¦è¿” 回值å–代原æ¥ä¼ å…¥çš„值,所以我们把它列在 OUTPUT: 部分,而ä¸æ˜¯ RETVAL。

+

XSUBPP 程åº

+

xsubpp 程åºå°† .xs 文件中的 XS 代ç ç¿»è¯‘æˆ C 代ç ï¼Œå­˜å‚¨åœ¨ä¸€ä¸ªåŽç¼€ä¸º .c 的文件中。创建的 C 代ç å°†èƒ½åœ¨ Perl 中使用 C 的函数。

+

TYPEMAP 文件

+

xsubpp 程åºä½¿ç”¨ä¸€äº›è§„则将 Perl çš„æ•°æ®ï¼ˆæ ‡é‡ï¼Œæ•°ç»„等等)转æ¢æˆ C çš„ æ•°æ®ç±»åž‹ï¼ˆint,char 等等)。这些规则存储在 typemap 文件中 ($PERLLIB/ExtUtils/typemap)。这个文件å¯ä»¥åˆ†ä¸ºä¸‰ä¸ªéƒ¨åˆ†ã€‚

+

第一部分将å„ç§ C çš„æ•°æ®ç±»åž‹æ˜ å°„到一个对应于 Perl æ•°æ®ç±»åž‹çš„一个å字。 第二部分是 xsubpp 用æ¥å¤„ç†è¾“å…¥å‚æ•°çš„ C 代ç ã€‚ç¬¬ä¸‰éƒ¨åˆ†åŒ…å« xsubpp 处ç†è¾“出å‚æ•°çš„ C 代ç ã€‚

+

让我们æ¥çœ‹çœ‹ä¸ºæˆ‘们的扩展而创建的 .c 文件的一部分。这个文件å为 Mytest.c:

+
        XS(XS_Mytest_round)
+        {
+            dXSARGS;
+            if (items != 1)
+                croak("Usage: Mytest::round(arg)");
+            {
+                double  arg = (double)SvNV(ST(0));      /* XXXXX */
+                if (arg > 0.0) {
+                        arg = floor(arg + 0.5);
+                } else if (arg < 0.0) {
+                        arg = ceil(arg - 0.5);
+                } else {
+                        arg = 0.0;
+                }
+                sv_setnv(ST(0), (double)arg);   /* XXXXX */
+            }
+            XSRETURN(1);
+        }
+

注æ„到两行注释了的“XXXXXâ€ã€‚如果你检查 typemap 文件的第一部分,你将看到 doubles 是类型 T_DOUBLE。在 INPUT 一段中,一个 T_DOUBLE çš„å‚数通过调用 SvNV 函数赋值给 arg å˜é‡ã€‚类似的,在 OUTPUT 一段中,arg 一旦有了最åŽçš„ 值,通过 sv_setnv 函数把它传递到调用的函数中。这两函数在 perlguts 中有详细解释。对于“ST[0]â€çš„å«ä¹‰å°†åœ¨å‚数栈中说明。

+

对于输出å‚数的警告

+

一般而言,ä¸è¦åœ¨æ‰©å±•ä¸­ä¿®æ”¹è¾“入的å‚数,åƒä¾‹å­ 3 那样。而应当以一个数组 çš„å½¢å¼è¿”回多个值,让调用者æ¥å¤„ç†ï¼ˆä¹‹åŽçš„例å­ä¸­ï¼Œæˆ‘们将这样åšï¼‰ã€‚然而, 为了能与调用已ç»å­˜åœ¨çš„ C 函数(这些函数通常是修改输入å‚数的)兼容,这 ç§åšè¿˜æ˜¯å¯ä»¥çš„。

+

例å­ 4

+

在这个例å­ä¸­ï¼Œæˆ‘们è¦å†™ä¸€ä¸ªä¸Žå·²ç»å®šä¹‰çš„ C 库交互。首先,我们创建一个自 己的库,然åŽè®© h2xs 写 .pm å’Œ .xs 文件。

+

在与 Mytest åŒä¸€å±‚目录内创建一个å为 Mytest2 的新目录。在 Mytest2 目录 中,创建å¦ä¸€ä¸ªå« mylib 的目录,cd 到这个目录。

+

在这里,我们è¦åˆ›å»ºä¸€äº›äº§ç”Ÿæµ‹è¯•åº“的文件,包括一个 C æºæ–‡ä»¶å’Œä¸€ä¸ªå¤´æ–‡ä»¶ï¼Œè¿˜ è¦åœ¨è¿™ä¸ªç›®å½•ä¸­åˆ›å»ºä¸€ä¸ª Makefile.PL。然åŽä½¿åœ¨ Mytest2 中è¿è¡Œ make 时自 动执行 Makefile.PL 产生 Makefile。

+

在 mylib 目录中,创建一个åƒè¿™æ ·çš„ mylib.h 文件:

+
        #define TESTVAL 4
+
+        extern double   foo(int, long, const char*);
+

同时创建一个 mylib.c 文件:

+
        #include <stdlib.h>
+        #include "./mylib.h"
+
+        double
+        foo(int a, long b, const char *c)
+        {
+                return (a + b + atof(c) + TESTVAL);
+        }
+

最åŽåˆ›å»ºè¿™æ ·ä¸€ä¸ª Makefile.PL 文件:

+
        use ExtUtils::MakeMaker;
+        $Verbose = 1;
+        WriteMakefile(
+            NAME   => 'Mytest2::mylib',
+            SKIP   => [qw(all static static_lib dynamic dynamic_lib)],
+            clean  => {'FILES' => 'libmylib$(LIB_EXT)'},
+        );
+
+
+        sub MY::top_targets {
+                '
+        all :: static
+
+        pure_all :: static
+
+        static ::       libmylib$(LIB_EXT)
+
+        libmylib$(LIB_EXT): $(O_FILES)
+                $(AR) cr libmylib$(LIB_EXT) $(O_FILES)
+                $(RANLIB) libmylib$(LIB_EXT)
+
+        ';
+        }
+

在“$(AR)â€å’Œâ€œ$(RANLIB)â€çš„行首,确信你使用的是一个制表符而ä¸æ˜¯ä¸€ä¸ªç©ºæ ¼ã€‚ 如果你用的是空格,make å°†ä¸èƒ½æ­£å¸¸è¿è¡Œã€‚在 Win32 系统中$(AR)的“crâ€å‚æ•° ä¸æ˜¯å¿…è¦çš„。

+

现在,我们è¦åˆ›å»ºæœ€é«˜å±‚çš„ Mytest2 文件。转到 Mytest2 的上层目录,è¿è¡Œä¸‹ é¢çš„命令:

+
        % h2xs -O -n Mytest2 ./Mytest2/mylib/mylib.h
+

这将输出一个警告è¦è¦†ç›– Mytest2,这没有关系。我们的文件是在 Mytest2/mylib,ä¸ä¼šè¢«è¦†ç›–的。

+

h2xs 产生的普通 Makefile.PL 是ä¸ä¼šçŸ¥é“ mylib 目录的。我们需è¦å‘Šè¯‰å®ƒè¿™ 有一个å­ç›®å½•ï¼Œæˆ‘们将在里é¢åˆ›å»ºä¸€ä¸ªåº“。åƒè¿™æ ·æ·»åŠ ä¸€ä¸ª MYEXTLIB å‚数到 WriteMakefile 调用中:

+
        WriteMakefile(
+            'NAME'      => 'Mytest2',
+            'VERSION_FROM' => 'Mytest2.pm', # finds $VERSION
+            'LIBS'      => [''],   # e.g., '-lm'
+            'DEFINE'    => '',     # e.g., '-DHAVE_SOMETHING'
+            'INC'       => '',     # e.g., '-I/usr/include/other'
+            'MYEXTLIB' => 'mylib/libmylib$(LIB_EXT)',
+        );
+

然åŽåœ¨æœ€åŽåŠ å…¥ä¸€ä¸ªå‡½æ•°ï¼ˆè¿™å°†è¦†ç›–å·²ç»å­˜åœ¨çš„函数)。记得使用制表符缩进以 “cdâ€å¼€å¤´çš„那一行ï¼

+
        sub MY::postamble {
+        '
+        $(MYEXTLIB): mylib/Makefile
+                cd mylib && $(MAKE) $(PASSTHRU)
+        ';
+        }
+

修改 MANIFEST 文件使它准确å映在我们扩展里的内容。“mylibâ€è¿™ä¸€è¡Œè¦ç”¨è¿™ 三行替æ¢äº†ï¼š

+
        mylib/Makefile.PL
+        mylib/mylib.c
+        mylib/mylib.h
+

为了使我们的å字空间ä¸è¢«æ±¡æŸ“,编辑 .pm 文件并修改 @EXPORT 为 EXPORT_OK。最åŽï¼Œåœ¨ .xs 文件中,编辑 #include 行:

+
        #include "mylib/mylib.h"
+

然åŽåœ¨ .xs 文件末尾加入下é¢çš„函数定义:

+
        double
+        foo(a,b,c)
+                int             a
+                long            b
+                const char *    c
+            OUTPUT:
+                RETVAL
+

现在,我们需è¦åˆ›å»ºä¸€ä¸ª typemap 文件,因为 Perl 现在还ä¸æ”¯æŒ const char* 类型。 在 Mytest2 目录中,创建一个å为 typemap 的文件,并写入:

+
        const char *    T_PV
+

好了,现在在最顶层è¿è¡Œ Makefile.PLå§ã€‚注æ„在 mylib 目录中也åŒæ—¶ç”Ÿæˆäº† 一个 Makefile 文件。è¿è¡Œ make 然åŽè§‚察到它确实进入 mylib 目录中,在那 里也è¿è¡Œäº† make。

+

编辑 test.pl 脚本,修改 BEGIN å—为输出“1..4â€ï¼Œç„¶åŽåœ¨è„šæœ¬çš„æœ«å°¾åŠ å…¥ä¸‹é¢ å‡ è¡Œï¼š

+
        print &Mytest2::foo(1, 2, "Hello, world!") == 7 ? "ok 2\n" : "not ok 2\n";
+        print &Mytest2::foo(1, 2, "0.0") == 7 ? "ok 3\n" : "not ok 3\n";
+        print abs(&Mytest2::foo(0, 0, "-3.4") - 0.6) <= 0.01 ? "ok 4\n" : "not ok 4\n";
+

(当处ç†æµ®ç‚¹æ•°çš„比较,最好ä¸è¦æ£€æŸ¥å®ƒä»¬æ˜¯å¦ç›¸ç­‰ï¼Œè€Œæ˜¯è€ƒå¯ŸæœŸæœ›å€¼ä¸ŽçœŸå®žå€¼ 的差是å¦æ¯”æŸä¸ªæ•°ï¼ˆç§°ä¸ºè¯¯å·®ï¼Œepsilon)å°ã€‚在这里,我们使用 0.01。)

+

运行“make test”,应该是正常的å§ã€‚

+

什么å‘生了?

+

不åƒå‰ä¸€ä¸ªä¾‹å­ï¼Œæˆ‘们现在是对一个真实的 include 文件使用 h2xs。这对 .pm å’Œ .xs 文件都带æ¥å¥½å¤„。

+
    +
  • 在 .xs 文件中,现在有一个 #include 指令引入一个到 mylib.h 头文件的ç»å¯¹ 路径。我们修改这个路径为相对路径,这样如果需è¦å¯ä»¥ç§»åŠ¨æ‰©å±•çš„目录。
  • +
  • 现在一些新的 C 代ç åŠ å…¥åˆ° .xs 文件中。constant 函数的功能是让头文件中使用 #define 的值能被 Perl 访问(通过 TESTVAL 或者 &Mytest2::TESTVAL)。一些 XS 代ç ä¹Ÿèƒ½å¤Ÿè°ƒç”¨ constant 函数。
  • +
  • .pm 文件最åˆå°† TESTVAL å字放在 @EXPORT 数组中。这å¯èƒ½ä¼šå¯¼è‡´åå­— 冲çªã€‚一个更好的规则是如果 #define åªæ˜¯è¢« C 的函数使用,而ä¸æ˜¯ç”¨æˆ·ï¼Œé‚£ 么è¦ä»Ž @EXPORT 中移除。或者,如果你ä¸ä»‹æ„使用å˜é‡çš„全称(“full qualified nameâ€ï¼‰ï¼Œä½ å¯ä»¥æŠŠ @EXPORT 中的大部分甚至全部放到 @EXPORT_OK 数组中。
  • +
  • 如果我们的 include 文件也有 #include 指令,h2xs ä¸èƒ½å¤„ç†ã€‚现在还没有好的 解决办法。
  • +
  • 我们还è¦å‘Šè¯‰ Perl 在 mylib å­ç›®å½•ä¸­æˆ‘们建了一个库。这åªè¦åœ¨ WriteMakefile 的调用中添加一个 MYEXTLIB å˜é‡ï¼Œæ›¿æ¢ postamble 函数为 cd 到å­ç›®å½•å¹¶è¿è¡Œ make。库的 Makefile.PL 有点å¤æ‚,但是也ä¸ä¼šå¤ªå¤æ‚。 我们å†æ¬¡æ›¿æ¢ postamble 函数,加入我们的代ç ã€‚这个代ç åªæ˜¯ç®€å•çš„指定这 个库是一个é™æ€å­˜æ¡£åº“(与动æ€å¯¼å…¥åº“对应),然åŽæ供创建的命令。
  • +
+

解æž .xs 文件

+

"â€œä¾‹å­ 4â€" 中的 .xs 文件包å«äº†ä¸€äº›æ–°çš„元素。è¦ç†è§£è¿™äº›å…ƒç´ çš„å«ä¹‰ï¼Œ 请注æ„这一行:

+
        MODULE = Mytest2                PACKAGE = Mytest2               
+

在此之å‰çš„代ç æ˜¯ plain C 代ç ï¼ŒæŒ‡å‡ºè¦åŒ…å«çš„头文件和定义一些方便使用的函 数。这一部分是ä¸è½¬æ¢çš„。编译器会跳过内嵌的 POD 文档,在 C æ–‡ä»¶ä¸­è¾“å‡ºåŒ æ ·çš„ä»£ç ã€‚

+

在此之åŽçš„是 XSUB 函数的说明。这些说明由 xsubpp ç¿»è¯‘æˆ C 代ç ã€‚翻译åŽçš„ C 函数是按 Perl 调用的规则,能被 Perl 的解释器所看的。

+

特别è¦æ³¨æ„ constant 函数。在产生的 .xs 文件中这个å字出现了两次:一 次在第一部分,作为一个 static C 函数,å¦ä¸€æ¬¡åœ¨ç¬¬äºŒéƒ¨åˆ†ï¼Œåœ¨å®šä¹‰ä¸€ä¸ªä½¿ç”¨è¿™ 个 static C 函数的 XSUB 接å£æ—¶ã€‚

+

这对 .xs 文件æ¥è¯´æ˜¯éžå¸¸å…¸åž‹çš„。通常 .xs 文件æ供了对已ç»å­˜åœ¨çš„ C 函数 的接å£ã€‚C 函数是在别的地方定义(在一个外部的库或者在 .xs 文件的第一部 分),而这个函数的 Perl 接å£ï¼ˆä¾‹å¦‚“Perl glueâ€ï¼‰åœ¨ .xs 文件的第二部分。 而在 "â€œä¾‹å­ 1â€""â€œä¾‹å­ 2â€" å’Œ "â€œä¾‹å­ 3â€" 中,所有的事情都在“Perl glueâ€ä¸­å®Œæˆï¼Œè¿™æ˜¯ä¸€ä¸ªä¸ç¬¦åˆè¿™ä¸€è§„则的特例。

+

给 XSUB å‡è‚¥

+

"â€œä¾‹å­ 4â€" .xs 文件的第二部分包å«äº†å¯¹ XSUB 的如下æ述:

+
        double
+        foo(a,b,c)
+                int             a
+                long            b
+                const char *    c
+            OUTPUT:
+                RETVAL
+

注æ„到和 "â€œä¾‹å­ 1â€""â€œä¾‹å­ 2â€" å’Œ "â€œä¾‹å­ 3â€" 相比,这个æè¿°ä¸åŒ…å« Perl 函数 foo 调用使用的真正代ç 。为了明白这里究竟是怎么回事,我们 å¯ä»¥åŠ å…¥ä¸€ä¸ª CODE 部分到这个 XSUB:

+
        double
+        foo(a,b,c)
+                int             a
+                long            b
+                const char *    c
+            CODE:
+                RETVAL = foo(a,b,c);
+            OUTPUT:
+                RETVAL
+

这两个 XSUB 几乎产生相åŒçš„ C 代ç ï¼šxsubpp 编译器很èªæ˜Žï¼Œå®ƒèƒ½å¤Ÿä»Žè¿™ä¸ª XSUB æ述的头两行推测出 CODE: 部分。那 OUTPUT: 部分呢?这也一样。 OUTPUT: 部分完全å¯ä»¥åŽ»æŽ‰ã€‚CODE: 或者 PPCODE: 没有指定 时,xsubpp 知é“它需è¦äº§ç”Ÿä¸€ä¸ªå‡½æ•°è°ƒç”¨éƒ¨åˆ†ï¼ŒåŒæ ·ä¼šäº§ç”Ÿä¸€ä¸ª OUTPUT 部 分。这样我们å¯ä»¥æŠŠè¿™ä¸ª XSUB 缩å‡æˆï¼š

+
        double
+        foo(a,b,c)
+                int             a
+                long            b
+                const char *    c
+

是ä¸æ˜¯ä¹Ÿå¯ä»¥å¯¹"â€œä¾‹å­ 2â€" çš„ XSUB 进行这样的æ“作:

+
        int
+        is_even(input)
+                int     input
+            CODE:
+                RETVAL = (input % 2 == 0);
+            OUTPUT:
+                RETVAL
+

如果你è¦è¿™æ ·åšçš„è¯ï¼Œå¿…须定义一个 C 函数 int is_even(int input)。在 "è§£æž .xs 文件"一节中,我们知é“这个定义应当放在 .xs 文件的第一部分。 这样一个 C 函数就å¯ä»¥ï¼š

+
        int
+        is_even(int arg)
+        {
+                return (arg % 2 == 0);
+        }
+

一个简å•çš„ #define 也å¯ä»¥ï¼š

+
        #define is_even(arg)    ((arg) % 2 == 0)
+

在 .xs 文件的第一部分有了这些之åŽï¼Œâ€œPerl glueâ€éƒ¨åˆ†å°±å¯ä»¥ç¼©å‡æˆè¿™æ ·

+
        int
+        is_even(input)
+                int     input
+

这个把粘åˆéƒ¨åˆ†å’Œå·¥ä½œéƒ¨åˆ†åˆ†ç¦»æ˜¯è¦ä»˜å‡ºä»£ä»·çš„ï¼šå¦‚æžœä½ æƒ³æ”¹å˜ Perl 的接å£ï¼Œ 你需è¦æ›´æ”¹ä»£ç çš„两个地方。但是这é¿å…了很多混乱,使工作部分的代ç ç‹¬ç«‹äºŽ Perl 调用的规定(事实上,在æ述上方的代ç ä¸éœ€è¦ç‰¹å®šä¸º Perl 而写。å¦ä¸€ 个版本的 xsubpp åŒæ ·å¯ä»¥æŠŠå®ƒç¿»è¯‘æˆ TCL glue 或者 Python glue)。

+

XSUB çš„å‚æ•°

+

在完æˆä¾‹å­ 4 åŽï¼Œæˆ‘们有了一个简å•çš„方法模拟一些接å£ä¸æ˜¯å¾ˆå¥½çš„库。现在 我们è¦è®¨è®ºä¸€ä¸‹ä¼ é€’ç»™ xsubpp 编译器的å‚数。

+

当你指定 .xs 文件中函数的å‚数时,你实际上是对æ¯ä¸ªå‚数传递了三个信æ¯ã€‚ 一是å‚数的顺åºï¼ŒäºŒæ˜¯å‚数的类型,由å‚数的类型声明(例如,int,char* ç­‰ 等)组æˆã€‚三是库函数调用的å字。

+

和 Perl 通过引用å‘函数传递å‚æ•°ä¸åŒï¼ŒC 是按值传递å‚数的,想è¦ä¿®æ”¹â€œå‚数†的数æ®ï¼Œå®žé™…çš„å‚数应该是这个数æ®çš„指针。因此这两个 C 函数的声明å¯èƒ½æœ‰ 完全ä¸åŒçš„语义:

+
        int string_length(char *s);
+        int upper_case_char(char *cp);
+

第一个å¯èƒ½æ˜¯æ£€æŸ¥ s 指å‘的字符数组,而第二个å¯èƒ½è§£é™¤ cp 的引用,åªæ“ 纵 *cp(返回值作为æˆåŠŸä¸Žå¦çš„指示)。在 Perl 里,你需è¦ç”¨ä¸åŒçš„æ–¹å¼æ¥ 使用这些函数。

+

你需è¦é€šè¿‡ç”¨ & æ›¿æ¢ * æ¥å‘Šè¯‰ xsubpp 这个信æ¯ã€‚& æ„æŒ‡è¿™ä¸ªå‚ æ•°éœ€è¦æŠŠåœ°å€ä¼ é€’给库函数。上é¢ä¸¤ä¸ªå‡½æ•°å¦‚果转æ¢æˆ XSUB çš„è¯ï¼Œåº”该是:

+
        int
+        string_length(s)
+                char *  s
+
+        int
+        upper_case_char(cp)
+                char    &cp
+

例如,对于这个例å­ï¼š

+
        int
+        foo(a,b)
+                char    &a
+                char *  b
+

这个函数的第一个 Perl å‚数将当作一个字符赋值给å˜é‡ a,它的地å€ä¹Ÿå°†ä¼ é€’ 给函数 foo。第二个 Perl å‚数将当作一个字符串指针赋值给å˜é‡ b。b çš„ 将传递给函数 foo。xsubpp 产生的函数 foo 的调用是这样的:

+
        foo(&a, b);
+

xsubpp 对这样的å‚数列表的解æžæ˜¯å®Œå…¨ä¸€æ ·çš„:

+
        char    &a
+        char&a
+        char    & a
+

但是为了更容易ç†è§£ï¼Œæœ€å¥½æŠŠâ€œ&â€æ”¾åœ¨é è¿‘å˜é‡å,远离å˜é‡ç±»åž‹ï¼ŒæŠŠâ€œ*â€æ”¾åœ¨é  è¿‘å˜é‡ç±»åž‹ï¼Œè¿œç¦»å˜é‡å。这样åšæ˜¯ä¸ºäº†æ–¹ä¾¿æ˜Žç™½ä½ å°†è¦ä¼ é€’什么到 C 函数中, è¦ä¼ é€’的就是最åŽä¸€æ çš„东西。

+

你è¦ç”¨å¾ˆå¤§åŠªåŠ›æ‰èƒ½åšåˆ°ä¼ é€’给函数它想è¦çš„æ•°æ®ç±»åž‹ã€‚但是这对将æ¥ä¼šå‡å°‘很多 麻烦。

+

参æ•°æ ˆ

+

除了第一个例å­ï¼Œå¦‚果仔细看å‰å‡ ä¸ªä¾‹å­äº§ç”Ÿçš„ C 代ç ï¼Œä½ ä¼šå‘现“ST(n)â€å‡ºçŽ° 了很多次,这里 n 通常是 0。“STâ€äº‹å®žä¸Šæ˜¯ä¸€ä¸ªæŒ‡å‘å‚数栈第 n 个å‚æ•°çš„å®ã€‚ ST(0)就是栈的第一个å‚数,所以第一个å‚数传递给了 XSUB,ST(1) æ˜¯ç¬¬äºŒä¸ªå‚ æ•°ï¼Œä»¥æ­¤ç±»æŽ¨ã€‚

+

当你在 .xs 文件中列出 XSUB çš„å‚数时,这就告诉 xsubpp 哪个å‚数对应于 栈内的第几个å‚数(例如,列出的第一个å‚数就是第一个å‚数,等等)。如果你 ä¸æ˜¯åƒå‡½æ•°ä¸­é‚£æ ·åˆ—出å‚数,这将导致很严é‡çš„åŽæžœã€‚

+

参数栈内的真实值是传入值的地å€ã€‚当一个å‚数列在 OUTPUT 中,对应的它将是 在栈内的一个值(例如,当它是第一个å‚数则是 ST(0))。你å¯ä»¥é€šè¿‡ä¾‹å­ 3 产生的 C 代ç éªŒè¯è¿™ä¸€ç‚¹ã€‚round() XSUB 函数的代ç ä¸­æœ‰è¿™æ ·å‡ è¡Œï¼š

+
        double  arg = (double)SvNV(ST(0));
+        /* Round the contents of the variable arg */
+        sv_setnv(ST(0), (double)arg);
+

arg å˜é‡ç”± ST(0) 中的值æ¥åˆå§‹åŒ–,然åŽåœ¨å‡½æ•°çš„末尾存储回 ST(0)。

+

XSUB 是å…许返回列表的,ä¸æ˜¯ä»…ä»…æ ‡é‡ã€‚这需è¦ä»¥ä¸€ç§ç²¾ç»†çš„æ–¹å¼å¯¹æ ˆ ST(0)〠ST(1) 等等的值进行æ“作。更详细的情况请å‚考 perlxs

+

XSUB 也å…许é¿å…从 Perl 函数å‚数到 C 函数å‚数的自动转æ¢ã€‚å‚考 perlxs。 尽管å¯ä»¥è‡ªåŠ¨è½¬æ¢ï¼Œä¸€äº›äººå®æ„¿é€šè¿‡è§‚察 ST(i) æ¥è‡ªå·±è½¬æ¢ã€‚他们说这样会 使 XSUB 的调用的逻辑性更强。(*这里å¯èƒ½ä¸å‡†ç¡®ï¼Œå› ä¸ºæˆ‘ä¸ç†è§£*ï¼‰å°±åƒ "“给 XSUB å‡è‚¥â€" 中分离“Perl glueâ€å’Œâ€œè‹¦åŠ›ï¼ˆworkhorse)â€çš„代价一样。

+

XSUBs are also allowed to avoid automatic conversion of Perl function arguments to C function arguments. See perlxs for details. Some people prefer manual conversion by inspecting ST(i) even in the cases when automatic conversion will do, arguing that this makes the logic of an XSUB call clearer. Compare with "Getting the fat out of XSUBs" for a similar tradeoff of a complete separation of "Perl glue" and "workhorse" parts of an XSUB.

+

While experts may argue about these idioms, a novice to Perl guts may prefer a way which is as little Perl-guts-specific as possible, meaning automatic conversion and automatic call generation, as in "Getting the fat out of XSUBs". This approach has the additional benefit of protecting the XSUB writer from future changes to the Perl API.

+

扩展你的扩展

+

某些时候,你å¯èƒ½æƒ³æ供一些å¦å¤–的方法或者函数æ¥ä½¿ Perl 和你的扩展之间的 接å£å’Œæ›´ç®€å•æˆ–者容易明白。这些函数应该è¦æ”¾åœ¨ .pm 文件中。它们是在扩展 本身被导入时自动导入还是åªåœ¨è°ƒç”¨æ—¶æ‰è¢«å¯¼å…¥å–决于函数的定义放在 .pm æ–‡ 件的什么地方。你å¯ä»¥æŸ¥çœ‹ AutoLoader,它给出å¦å¤–一ç§ä¿å­˜å’Œå¯¼å…¥å…¶å®ƒå‡½ 数的办法。

+

为你的扩展æ供文档

+

一定è¦ä¸ºä½ çš„扩展æ供文档。文档的内容放在 .pm 文件中。这个文件通常会æ 供给 pod2man,然åŽå†…嵌的文档将转æ¢æˆ manpage æ ¼å¼æ”¾åˆ° blib 目录中。在 安装扩展的时候,将å¤åˆ¶åˆ° Perl çš„ manpage 目录中。

+

在 .pm 文件中,你也å¯ä»¥äº¤æ›¿çš„写 Perl 代ç å’Œæ–‡æ¡£ã€‚事实上,如果你想使用 autoloading 方法,你必须这样åšï¼Œå°±åƒåœ¨ .pm 文件中注释中说的那样。

+

关于 pod çš„æ ¼å¼ï¼Œè¯·å‚考 perlpod

+

安装你的扩展

+

一旦你的扩展完æˆå¹¶é€šè¿‡æ‰€æœ‰çš„测试之åŽï¼Œå®‰è£…是éžå¸¸ç®€å•çš„:你åªè¦è¿è¡Œ “make installâ€ã€‚你需è¦æœ‰å¯¹ Perl 安装目录的写æƒé™æˆ–者让你的系统管ç†å‘˜æ¥ 为你è¿è¡Œã€‚

+

还有一个办法,你å¯ä»¥æŒ‡å®šé‡Šæ”¾æ‰©å±•æ–‡ä»¶çš„目录,在 make install 之åŽåŠ ä¸Š “PREFIX=/destination/directoryâ€å°±å¯ä»¥äº†ï¼ˆå¦‚果你有 brain-dead 版本的 make,你å¯ä»¥æ”¾åœ¨ make å’Œ install 中间)。这对创建一个最终对多个系统å‘è¡Œ 的扩展是很有用的。你å¯ä»¥åªæŠŠæ–‡ä»¶æ”¾åˆ°ç›®æ ‡ç›®å½•ä¸­ï¼Œç„¶åŽå¯¹ä½ çš„目标系统å‘è¡Œ 它们。

+

例å­ 5

+

在这个例å­ä¸­ï¼Œæˆ‘们将对å‚数栈进行一些æ“作。å‰é¢çš„例å­ä¸­å…¨éƒ¨åªè¿”回一个值。 现在,我们è¦åˆ›å»ºä¸€ä¸ªè¿”回一个数组的扩展。

+

这个扩展是éžå¸¸ Unix 化(Unix-oriented)的(statfs 结构和 statfs 系统调 用等等)。如果你ä¸æ˜¯åœ¨ Unix 系统下è¿è¡Œï¼Œä½ å¯ä»¥ç”¨è¿”å›žå¤šä¸ªå€¼çš„å…¶å®ƒå‡½æ•°æ¥ ä»£æ›¿ã€‚æˆ–è€…å¹²è„†ä¸å®Œæˆè¿™ä¸ªä¾‹å­ã€‚如果你修改 XSUB,请记得修改测试æ¥ç¬¦åˆä½ çš„ 修改。

+

This extension is very Unix-oriented (struct statfs and the statfs system call). If you are not running on a Unix system, you can substitute for statfs any other function that returns multiple values, you can hard-code values to be returned to the caller (although this will be a bit harder to test the error case), or you can simply not do this example. If you change the XSUB, be sure to fix the test cases to match the changes.

+

回到 Mytest 目录,在 Mytest.xs 末尾加入这些代ç ï¼š

+
        void
+        statfs(path)
+                char *  path
+            INIT:
+                int i;
+                struct statfs buf;
+
+            PPCODE:
+                i = statfs(path, &buf);
+                if (i == 0) {
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_bavail)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_bfree)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_blocks)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_bsize)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_ffree)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_files)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_type)));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_fsid[0])));
+                        XPUSHs(sv_2mortal(newSVnv(buf.f_fsid[1])));
+                } else {
+                        XPUSHs(sv_2mortal(newSVnv(errno)));
+                }
+

你还è¦åœ¨ .xs 文件的头部,在 include “XSUB.hâ€åŽä¸€è¡ŒåŠ å…¥ä¸‹é¢çš„代ç ï¼Œ

+
        #include <sys/vfs.h>
+

然åŽåœ¨ test.pl 中修改 BEGIN å—为“1..11â€ï¼ŒåŠ å…¥ä¸‹é¢ä¸€æ®µï¼š

+
        @a = &Mytest::statfs("/blech");
+        print ((scalar(@a) == 1 && $a[0] == 2) ? "ok 10\n" : "not ok 10\n");
+        @a = &Mytest::statfs("/");
+        print scalar(@a) == 9 ? "ok 11\n" : "not ok 11\n";
+

这个例å­ä¸­çš„新东西

+

这个例å­å¢žåŠ äº†å¾ˆå¤šæ–°æ¦‚念,下é¢ä¸€ä¸€è¿›è¡Œè§£é‡Šã€‚

+
    +
  • INIT: 指令包å«äº†å°†åœ¨å‚数栈被转æ¢ä¹‹åŽç«‹å³åŠ å…¥çš„代ç ã€‚C ä¸å…许å˜é‡çš„声明 放在函数的任æ„ä½ç½®ã€‚所以这是通常是最好的办法æ¥å£°æ˜Ž XSUB 需è¦çš„局部å˜é‡ (或者你å¯ä»¥æŠŠ PPCODE: 全放到一个尖括å·é‡Œï¼Œç„¶åŽæŠŠè¿™ä¸ªå£°æ˜Žæ”¾åˆ°æœ€é¡¶ 部)。
  • +
  • 这个函数还根æ®è°ƒç”¨ statfs çš„æˆåŠŸä¸Žå¦è¿”回ä¸åŒæ•°é‡çš„å‚数。如果å‘生错误, 错误å·å°†åšä¸ºåªæœ‰ä¸€ä¸ªå…ƒç´ çš„数组返回。如果调用æˆåŠŸï¼Œå°†è¿”回一个 9 个元素 的数组。由于åªä¼ é€’了一个å‚数给这个函数,我们对返回的栈进行扩充使之能够 放入 9 个元素。

    我们通过 PPCODE: 指令而ä¸æ˜¯ CODE: 指令æ¥è¾¾åˆ°è¿™ä¸ªç›®çš„。PPCODE: 告诉 xsubpp 我们将自己æ“作返回值,并把返回值放到å‚数栈中。

  • +
  • 当想è¦æŠŠè¦è¿”回给调用者的值放到栈中时,我们使用了一系列以“PUSHâ€å¼€å¤´çš„å®ã€‚ 它有五ç§ä¸åŒçš„类型,分别针对放置整数ã€éžè´Ÿæ•´æ•°ã€åŒç²¾åº¦æ•°ã€å­—符串和 Perl æ ‡é‡ã€‚在这个例å­ä¸­ï¼Œæˆ‘们放置了一个 Perl æ ‡é‡åˆ°æ ˆä¸­ï¼ˆå®žé™…上,这是 唯一能够用于返回多个值的å®ï¼‰ã€‚

    XPUSH* å®ä¼šè‡ªåŠ¨æ‰©å……返回栈防止溢出。你å¯ä»¥æŒ‰ä½ æƒ³è®©è°ƒç”¨çš„程åºçœ‹åˆ°çš„é¡ºåº æ”¾åˆ°æŠŠå®ƒä»¬æ ˆä¸­ã€‚

  • +
  • 放å…¥ XSUB 返回栈的值事实上是暂时的(mortal)SV。所以一旦值被调用程åºå¤ 制,这些ä¿å­˜è¿”回值的标é‡å°†ä¼šè¢«é‡Šæ”¾ã€‚如果它们ä¸æ˜¯æš‚时的,则在 XSUB 函数 返回之åŽå®ƒä»¬è¿˜å°†ç»§ç»­å­˜åœ¨ï¼Œä½†æ˜¯å·²ç»ä¸èƒ½å†è®¿é—®äº†ã€‚这将导致内存泄æ¼ã€‚
  • +
  • + 如果我们更关心代ç çš„å¯æ‰§è¡Œæ€§ï¼ˆperformance),而ä¸æ˜¯ä»£ç çš„ç®€æ´ ï¼ˆcompactness),在那æ¡æˆåŠŸçš„分支我们å¯ä»¥ä¸ä½¿ç”¨ XPUSHs å®ï¼Œè€Œç”¨ PUSHs å®ï¼Œè¿™å¯ä»¥åœ¨æ”¾å…¥è¿”回值之å‰é¢„先扩充栈: +
            EXTEND(SP, 9);
    +

    这æ ·åšçš„代价是你需è¦å…ˆè®¡ç®—返回值的数目(虽然过多扩充栈一般也ä¸ä¼šæœ‰ä»€ä¹ˆ å处,åªæ˜¯éœ€è¦æ›´å¤šçš„内存)。

    +

    同样,在那æ¡å¤±è´¥çš„分支,我们å¯ä»¥不用扩充栈,而直接使用 PUSHs:Perl 函数的引用在 XSUB 的栈内,因此这个栈总是可以放入一个 返回值的。

    +
  • +
+

例å­ 6

+

在这个例å­ä¸­ï¼Œæˆ‘们将接å—一个数组的引用作为输入å‚数,然åŽè¿”回一个散列数 组的引用,用æ¥æ¼”示在 XSUB 中如何æ“纵å¤æ‚çš„ Perl æ•°æ®ç±»åž‹ã€‚

+

这个扩展有点ä¸å¤ªè‡ªç„¶ã€‚它是基于å‰é¢ä¾‹å­çš„代ç ã€‚它多次调用 statfs 函数, 接å—一个文件å数组的引用作为输入,然åŽè¿”回一个包å«æ¯ä¸ªæ–‡ä»¶æ•°æ®çš„散列数 组的引用。

+

回到 Mytest 目录,在 Mytest.xs 文件的末尾加入下é¢çš„代ç ï¼š

+
        SV *
+        multi_statfs(paths)
+                SV * paths
+            INIT:
+                AV * results;
+                I32 numpaths = 0;
+                int i, n;
+                struct statfs buf;
+
+                if ((!SvROK(paths))
+                    || (SvTYPE(SvRV(paths)) != SVt_PVAV)
+                    || ((numpaths = av_len((AV *)SvRV(paths))) < 0))
+                {
+                    XSRETURN_UNDEF;
+                }
+                results = (AV *)sv_2mortal((SV *)newAV());
+            CODE:
+                for (n = 0; n <= numpaths; n++) {
+                    HV * rh;
+                    STRLEN l;
+                    char * fn = SvPV(*av_fetch((AV *)SvRV(paths), n, 0), l);
+
+                    i = statfs(fn, &buf);
+                    if (i != 0) {
+                        av_push(results, newSVnv(errno));
+                        continue;
+                    }
+
+                    rh = (HV *)sv_2mortal((SV *)newHV());
+
+                    hv_store(rh, "f_bavail", 8, newSVnv(buf.f_bavail), 0);
+                    hv_store(rh, "f_bfree",  7, newSVnv(buf.f_bfree),  0);
+                    hv_store(rh, "f_blocks", 8, newSVnv(buf.f_blocks), 0);
+                    hv_store(rh, "f_bsize",  7, newSVnv(buf.f_bsize),  0);
+                    hv_store(rh, "f_ffree",  7, newSVnv(buf.f_ffree),  0);
+                    hv_store(rh, "f_files",  7, newSVnv(buf.f_files),  0);
+                    hv_store(rh, "f_type",   6, newSVnv(buf.f_type),   0);
+
+                    av_push(results, newRV((SV *)rh));
+                }
+                RETVAL = newRV((SV *)results);
+            OUTPUT:
+                RETVAL
+

然åŽåœ¨ test.pl 文件中修改 BEGIN å—中的“1..11â€ä¸ºâ€œ1..13â€ï¼ŒåŒæ—¶åŠ å…¥ä»¥ä¸‹çš„代ç ï¼š

+
        $results = Mytest::multi_statfs([ '/', '/blech' ]);
+        print ((ref $results->[0]) ? "ok 12\n" : "not ok 12\n");
+        print ((! ref $results->[1]) ? "ok 13\n" : "not ok 13\n");
+

这个例å­ä¸­çš„新东西

+

这个例å­ä¸­åˆå¼•å…¥äº†ä¸å°‘新的概念,以下是它们的æ述:

+
    +
  • 这个函数ä¸æ˜¯ä½¿ç”¨ typemap,而是声明接å—一个 SV*(标é‡ï¼‰å‚数,然åŽè¿”回一 个 SV* 值。在代ç ä¸­ï¼Œæˆ‘们处ç†ï¼ˆpopulating)这些标é‡ã€‚由于我们åªè¿”回一 个值,所以ä¸å¿…用 PPCODE: 指令,而是使用 CODE: å’Œ OUTPUT: 指令。
  • +
  • 当处ç†å¼•ç”¨æ—¶ï¼Œæˆ‘们一定è¦å°å¿ƒè°¨æ…Žã€‚在 INIT: å—中,首先检查 SvROK 的返回值是å¦ä¸ºçœŸï¼Œè¿™å¯ä»¥åˆ¤æ–­ paths 是å¦æ˜¯åˆæ³•çš„引用。然åŽéªŒè¯ paths 引 用的对象确实是一个数组。使用 SvRV æ¥è§£é™¤ paths 的引用,SvTYPE æ¥ å¾—åˆ°å®ƒçš„ç±»åž‹ã€‚è¿˜æœ‰ä¸€ä¸ªæµ‹è¯•æ˜¯ä½¿ç”¨ av_len(返回 -1 说明数组为空) æ¥æ£€ 测 paths 所引用的数组是å¦ä¸ºç©ºã€‚在三个测试没有都满足的è¯ï¼ŒXSRETURN_UNDEF å®ç”¨æ¥é€€å‡º XSUB 并返回undefined 值。
  • +
  • + 在这个 XSUB 中,我们æ“纵了几个数组。数组在内部用 AV* 指针表示。æ“作数组 的函数和å®ä¸Ž Perl 中了很类似:av_len 返回 AV* 中最大的索引,类似于 $#arrayï¼›av_fetch 通过索引从数组中得到一个标é‡çš„值;av_push 将一 个标é‡æ”¾åˆ°æ•°ç»„的末尾,如果必è¦çš„è¯ï¼Œè‡ªåŠ¨æ‰©å……数组。 +

    我们æ¯æ¬¡ä»Žè¾“入的数组中读入一个路径å,然åŽæŠŠç»“果按åŒæ ·çš„顺åºå­˜å‚¨åœ¨è¾“出 的数组(也就是 results)中。如果 statfs 失败了,放入返回数组中的值是失 败的错误å·ã€‚如果 statfs æˆåŠŸï¼Œæ”¾å…¥æ•°ç»„ä¸­çš„æ˜¯ä¸€ä¸ªåŒ…å« statfs 结构信æ¯çš„ 散列的引用。

    +

    和返回栈相åŒï¼Œå› ä¸ºæˆ‘们知é“有多少元素需è¦è¿”回,在放入数组之å‰æˆ‘们å¯ä»¥é¢„ 先扩充返回的数组(执行性能更好一些):

    +
            av_extend(results, numpaths);
    +
  • +
  • 我们在这个函数中åªæœ‰ä¸€ä¸ªæ•£åˆ—æ“作,使用 hv_store 对一个标é‡æŒ‰ä¸€ä¸ªå…³ 键值存储。散列是用 HV* 指针æ¥è¡¨ç¤ºã€‚和数组一样,XSUB 中æ“作散列的函数是 å’Œ Perl 中的是一一对应的。å‚考 perlguts å’Œ perlapi
  • +
  • 为了创建一个引用,我们使用了 newRV 函数。注æ„在这个例å­ï¼ˆå¾ˆå¤šéƒ½ä¸€ 样)中,å¯ä»¥æŠŠä¸€ä¸ª AV* 或者 HV* 类型转æ¢æˆ SV*。这å¯ä»¥ä½¿ä½ å¯ä»¥å¯¹æ•°ç»„〠散列ã€æ ‡é‡ç”¨ç›¸åŒçš„函数æ“作。与此相对,SvRV 函数åªè¿”回一个 SV*。因此 å¯èƒ½å¯¹äºŽä¸æ˜¯æ ‡é‡çš„情况(用 SvTYPE 检查)需è¦è½¬æ¢æˆåˆé€‚的类型。
  • +
  • 在这个例å­ä¸­ï¼Œxsubpp åªåšäº†ä¸€ç‚¹ç‚¹äº‹æƒ…,Mytest.xs å’Œ Mytest.c 的差别很 å°ã€‚
  • +
+

例å­ 7 (Coming Soon)

+

XPUSH args 和设置 RETVAL 和将返回值赋值给一个数组

+

例å­ 8 (Coming Soon)

+

设ç½® $!

+

例å­ 9 传递一个打开的文件给 XS

+

你å¯èƒ½è®¤ä¸ºç»™ XS 传递一个文件是很困难的,用到别å等等东西。其实并éžå¦‚此。

+

假设为了æŸä¸ªå¥‡æ€ªçš„ç†ç”±ï¼Œæˆ‘们需è¦åŒ…装标准 C 库函数 fputs()。这是所有 我们需è¦åšçš„事情:

+
        #define PERLIO_NOT_STDIO 0
+        #include "EXTERN.h"
+        #include "perl.h"
+        #include "XSUB.h"
+
+        #include <stdio.h>
+
+        int
+        fputs(s, stream)
+                char *          s
+                FILE *          stream
+

标准的 typemap 完æˆäº†çœŸæ­£çš„工作。

+

但是你没有看到 perlio 层åšçš„完美工作。这åªæ˜¯å¯ä»¥è°ƒç”¨æ ‡å‡†è¾“入输出函 æ•° fputs(),而对此一无所知。

+

标准 typemap æ供了三个 PerlIO * çš„å˜ä½“:InputStream (T_IN), InOutStream (T_INOUT) å’Œ OutputStream (T_OUT)。å•ç‹¬çš„ PerlIO * 被当作一个 T_INOUT。 The standard typemap offers three variants of PerlIO *: . A bare PerlIO * is considered a T_INOUT. If it matters in your code (see below for why it might) #define or typedef one of the specific names and use that as the argument or result type in your XS file.

+

The standard typemap does not contain PerlIO * before perl 5.7, but it has the three stream variants. Using a PerlIO * directly is not backwards compatible unless you provide your own typemap.

+

For streams coming from perl the main difference is that OutputStream will get the output PerlIO * - which may make a difference on a socket. Like in our example...

+

For streams being handed to perl a new file handle is created (i.e. a reference to a new glob) and associated with the PerlIO * provided. If the read/write state of the PerlIO * is not correct then you may get errors or warnings from when the file handle is used. So if you opened the PerlIO * as "w" it should really be an OutputStream if open as "r" it should be an InputStream.

+

Now, suppose you want to use perlio layers in your XS. We'll use the perlio PerlIO_puts() function as an example.

+

In the C part of the XS file (above the first MODULE line) you have

+
        #define OutputStream    PerlIO *
+    or
+        typedef PerlIO *        OutputStream;
+

And this is the XS code:

+
        int
+        perlioputs(s, stream)
+                char *          s
+                OutputStream    stream
+        CODE:
+                RETVAL = PerlIO_puts(stream, s);
+        OUTPUT:
+                RETVAL
+

We have to use a CODE section because PerlIO_puts() has the arguments reversed compared to fputs(), and we want to keep the arguments the same.

+

Wanting to explore this thoroughly, we want to use the stdio fputs() on a PerlIO *. This means we have to ask the perlio system for a stdio FILE *:

+
        int
+        perliofputs(s, stream)
+                char *          s
+                OutputStream    stream
+        PREINIT:
+                FILE *fp = PerlIO_findFILE(stream);
+        CODE:
+                if (fp != (FILE*) 0) {
+                        RETVAL = fputs(s, fp);
+                } else {
+                        RETVAL = -1;
+                }
+        OUTPUT:
+                RETVAL
+

Note: PerlIO_findFILE() will search the layers for a stdio layer. If it can't find one, it will call PerlIO_exportFILE() to generate a new stdio FILE. Please only call PerlIO_exportFILE() if you want a new FILE. It will generate one on each call and push a new stdio layer. So don't call it repeatedly on the same file. PerlIO()_findFILE will retrieve the stdio layer once it has been generated by PerlIO_exportFILE().

+

This applies to the perlio system only. For versions before 5.7, PerlIO_exportFILE() is equivalent to PerlIO_findFILE().

+

消除这些例å­ä¸­çš„问题

+

在文档的开头就æ到,如果你如果在这些例å­ä¸­é‡åˆ°ä¸€äº›é—®é¢˜çš„è¯ï¼Œå¯ä»¥çœ‹çœ‹è¿™ 些是ä¸æ˜¯èƒ½å¸®ä¸Šå¿™ã€‚

+
    +
  • + 对于 5.002 prior 到 gamma ç‰ˆæœ¬ï¼Œä¾‹å­ 1 的测试脚本å¯èƒ½ä¸èƒ½æ­£å¸¸è¿è¡Œã€‚ä½  è¦å°†â€œuse libâ€è¿™ä¸€è¡Œæ”¹ä¸ºï¼š +
            use lib './blib';
    +
  • +
  • + 对于 5.002 prior 到 5.002b1h 版本,h2xs æ²¡æœ‰è‡ªåŠ¨ç”Ÿæˆ test.pl。这æ„å‘³ç€ ä½ ä¸èƒ½ç”¨â€œmake testâ€æ¥è¿è¡Œæµ‹è¯•è„šæœ¬ã€‚你需è¦åœ¨â€œuse extensionâ€è¯­å¥å‰åŠ å…¥ï¼š +
            use lib './blib';
    +
  • +
  • + 对于 5.000 到 5.001 版本,需è¦ä½¿ç”¨ä¸‹ä¸€è¡Œè€Œä¸æ˜¯ä¸Šé¢é‚£ä¸€è¡Œï¼š +
            BEGIN { unshift(@INC, "./blib") }
    +
  • +
  • 这个文档å‡å®šä½ çš„å为“perlâ€å¯æ‰§è¡Œçš„程åºæ˜¯ Perl version 5。一些系统å¯èƒ½ä»¥ “perl5â€ä¸ºå安装 Perl version 5。
  • +
+

See also

+

更多信æ¯ï¼Œè¯·æŸ¥çœ‹ perlgutsperlapiperlxsperlmod å’Œ perlpod

+

Author

+

Jeff Okamoto <okamoto@corp.hp.com>

+

Dean Roehrich, Ilya Zakharevich, Andreas Koenig å’Œ Tim Bunce 修订和å助完æˆã€‚

+

PerlIO çš„æ料由 Lupe Christoph æ供,Nick Ing-Simmons 对此åšäº†ä¸€äº›å®Œå–„。

+

Last Changed

+

2002/05/08

+

TRANSLATORS

+

YE Wenbin

+ + diff --git a/POD/CN_html/pod2html.pl b/POD/CN_html/pod2html.pl new file mode 100644 index 0000000..7b47c3d --- /dev/null +++ b/POD/CN_html/pod2html.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +use v5.14; +use TOBYINK::Pod::HTML; +use Path::Tiny; + +#copied from the cpan document + +my $pod2html = "TOBYINK::Pod::HTML"->new( + pretty => 1, # nicely indented HTML + +##TODO: code_highlighting not work at the moment + +# code_highlighting => 1, # use PPI::HTML + # code_line_numbers => 1, + # code_styles => { # some CSS + # comment => 'color:green', + # keyword => 'font-weight:bold', + # } +); + +my $pod_dir = path("../CN"); +my @pod_files = $pod_dir->children; + + + +#rewrite the metacpan link to internal link + +sub rewrite_metacpan_link { + my $html_string = shift; + $html_string =~s!https://metacpan\.org/module/(\w+)!$1\.html!gr; +} + +foreach my $filename (@pod_files) { + my $file_name_pod = $filename->stringify; + my $file_name_html = $file_name_pod =~ s/pod/html/r; + my $pod_html = $pod2html->file_to_xhtml($file_name_pod); + $pod_html = rewrite_metacpan_link($pod_html); + path(path($file_name_html)->basename)->spew($pod_html); +} + +