2009年1月12日星期一

笔记:Intermediate Perl

Chapter 6 - Chapter 7

用Data::Dumper或YAML查看数据结构。
use YAML;
print Dump(\%some_hash);
用Storable存储数据结构到文件(store)、从文件中读取数据结构(retrieve)。
函数引用:
my %greets = (
Gilligan => \&gilligan_greets,
Skipper => \&skipper_greets,
Professor => \&professor_greets,
);
for my $person (qw(Skipper Gilligan)) {
$greets{$person}->('Professor');
}
闭包:In Perl terms, a closure is just a subroutine that references a lexical variable that has gone out of scope.
use File::Find;
my $callback;
{
my $count = 0;
$callback = sub { print ++$count, ": $File::Find::name\n" };
}
find($callback, '.');
可以通过$callback读取变量$count。
返回目录大小的闭包举例:
use File::Find;
sub create_find_callbacks_that_sum_the_size {
my $total_size = 0;
return(sub { $total_size += -s if -f }, sub { return $total_size });
}
my ($count_em, $get_results) = create_find_callbacks_that_sum_the_size( );
find($count_em, 'bin');
my $total_size = &$get_results( );
print "total size of bin is $total_size\n";
闭包是针对逻辑变量说di,具体:Closures are "closed" only on lexical variables, since lexical variables eventually go out of scope. Because a package variable (which is a global) never goes out of scope, a closure never closes on a package variable. All subroutines refer to the same single instance of the global variable.



Chapter 8

以标量初始化文件句柄:

  
open( my $fh, '>>', \$string_log )
        or die "Could not append to string! $!";

用IO::File新建文件句柄,可建立临时文件。

用IO::Tee同时输出到两个句柄:

  
use IO::Tee;

$tee_fh = IO::Tee->new( $log_fh, $scalar_fh );

print $tee_fh "The radio works in the middle of the ocean!\n";

用IO::Tee从$read_fh读入,同时输出到$log_fh,$scalar_fh:

  
use IO::Tee;

$tee_fh = IO::Tee->new( $read_fh, $log_fh, $scalar_fh );

# reads from $read_fh
my $message = <$tee_fh>;

# prints to $log_fh and $scalar_fh
print $tee_fh $message;

读目录:

  
opendir my $dh, '.' or die "Could not open directory: $!";

foreach my $file  ( readdir( $dh ) ) {
        print "Skipper, I found $file!\n";
        }

用IO::Dir读目录。

Chapter 9. Practical Reference Tricks

sort 之后array中各元素的位置:

  
my @input = qw(Gilligan Skipper Professor Ginger Mary_Ann);
my @sorted_positions = sort { $input[$a] cmp $input[$b] } 0..$#input;
my @ranks;
@ranks[@sorted_positions] = (1..@sorted_positions);
for (0..$#ranks) {
  print "$input[$_] sorts into position $ranks[$_]\n";
}

Chapter 10. Building Larger Programs

do xxx.pm如同xxx.pm中的代码是嵌于当前程序中一般,但xxx.pm仍保持自身的范围,逻辑变量及use strict之类不会影响到当前程序。

require xxx.pm会先检查Perl是否已经读入过xxx.pm,每个文件只会读一次。如果xxx.pm中有语法错误,程序会直接die挂掉。xxx.pm最后返回的值必须为真。

临时添加目录到@INC:perl -I/home/skipper/perl-lib /home/skipper/bin/get_us_home

Chapter 11. Introduction to Objects

继承:

  
package Cow;
use base qw(Animal);

使用父类的函数:

  
{ package Animal;
  sub speak {
    my $class = shift;
    print "a $class goes ", $class->sound, "!\n";
  }
}
{ package Mouse;
  @ISA = qw(Animal);
  sub sound { 'squeak' }
  sub speak {
    my $class = shift;
    $class-><span style="COLOR: #ff0000">SUPER::</span>speak;
    print "[but you can barely hear it!]\n";
  }
}

类函数调用:

  
my $beast = 'Class';
$beast->method(@args);

参数解析为('Class', @args),调用Class::method('Class', @args),如果没找到Class::method,就去Class的父类找。

Chapter 12-15

限制函数只能通过Class名/实例访问:
use Carp qw(croak);

sub instance_only {
  ref(my $self = shift) or croak "instance variable needed";
  ... use $self as the instance ...
}

sub class_only {
  ref(my $class = shift) and croak "class name needed";
  ... use $class as the class ...
}
记得在析构函数中调用$self->SUPER::DESTROY
弱引用(use WeakRef;),不增加引用对象的引用计数值,在引用计数变0时,弱引用会自动变undef。例子见13.7. Weakening the Argument。
检查实例是否属于某个类: $tv_horse->isa('Animal')
检查是否存在指定的类函数:
if ($tv_horse->can('eat')) {
  $tv_horse->eat('hay');
}
如果$self->some_method()找不到,就搜UNIVERSAL::some_method(),还找不到,就搜AUTOLOAD()。
Class::MethodMakerClass::Accessor帮助快速指定类属性,并生成类函数。
使用Exporter指定导出的函数:
package Navigate::SeatOfPants;
our @EXPORT = qw(guess_direction_toward);
our @EXPORT_OK = qw(ask_the_skipper_about get_north_from_professor);
use base qw(Exporter);
其中,@EXPORT指定use Navigate::SeatOfPants;时可用的函数,@EXPORT_OK指定Navigate::SeatOfPants qw/xxx yyy zzz/时可用的函数。
还有 %EXPORT_TAGS可以将函数分类。

Chapter 16-19

使用Module::Starter及Module::Build建立Perl模块。
cpan> readme Island::Plotting::Maps 看一个模块的说明。
写pod,大概就是=head1,=over,=item之类。
使用Test::More进行测试,tests指定跑几次测试。
use Test::More tests => 9;

{
$n = -1;
eval { sqrt($n) };
ok( $@, '$@ is set after sqrt(-1)' );
}

测试相关模块Test::Harness、
          Test::Manifest、Test::MockObject等
测试pod文档的模块Test::Pod。
分支测试Devel::Cover
自定义测试Test::Builder。

没有评论:

发表评论