14 September 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.

Util 是 Utility 的缩写,意为有用的工具。
此三模块以前看过但没用过,昨晚在 Perl Best Practices 里听 Damain Conway 又提及。觉得用处挺大的,就简单翻译下用途。需要的参阅 perldoc, 此三模块在 5.8 后为标准模块,安装 Perl 后就有了。

Scalar::Util

blessed $scalar

如果 $scalar 是一个对象的引用,则返回这个对象的类的名字,否则返回 undef

refaddr $scalar

如果 $scalar 是一个引用,则返回一个数字代表该引用的所指向的内存地址,否则返回 undef
这个可以对两个变量是否同一提供判断。

reftype $scalar

如果 $scalar 是一个引用,则返回相应的类型值(如 'SCALAR', 'HASH', 'ARRAY', 'CODE', 'Regexp'),否则返回 undef

readonly $scalar

如果 $scalar 只读返回真

openhandle $scalar

如果不是一个文件句柄或着该文件句柄没有开着的话,返回 undef
use Scalar::Util qw/openhandle/;

open(FH, 'nonexist');
print openhandle(*FH); # 返回 undef

open(FILE, 'exist');
print openhandle(*FILE); # 返回如 GLOB(0x162538c)
close(FILE);
print openhandle(*FILE); # 返回 undef

weaken $scalar/is_weak $scalar

使用这个对防止循环数据结构的内存泄露有帮助。详细参阅该书和 perldoc

dualvar NUM, STRING

设置一个变量在数字环境和字符串环境下返回不同的值。
$foo = dualvar 10, "Hello";
$num = $foo + 2;                    # 12
$str = $foo . " world";             # Hello world

looks_like_number, set_prototype etc.

参阅书籍或 perldoc Scalar::Util

List::Util

first { <condition> } @list

返回 @list 中满足该 condition 的第一个元素。该函数与 grep 有点类似,但它是搜寻到第一个匹配时就停止了,而 grep 要搜索完整个 @list

max/min @list

返回数组中用 >/< 号比较后的最大最小值

maxstr/minstr @list

返回数组中用 gt/lt 比较后的最大最小值

shuffle @list

象 ipod shuffle 一样,随机在 @list 挑一个元素

sum @list

对整个 @list 求和,然后返回值

reduce BLOCK LIST

这个其实挺有用的。上面的这些 max, min, first, sum 等都可以用 reduce 来操作。
该函数首先将 LIST 中的第一和第二个元素赋予 $a 和 $b (与 sort 有点类似),然后执行 BLOCK, 将其返回值赋予 $a, 然后取第三个元素赋予 $b, 再执行 BLOCK, 就这样多次执行,然后返回值。
$foo = reduce { $a < $b ? $a : $b } 1..10; # 这句与 min 1..10 一样效果
$foo = reduce { defined($a) ? $a : defined($b) ? $b : undef } undef, @list; # 这句效果与 $foo = first { defined($_) } @list 同
my $overall_probablity = reduce { $a * $b } @partial_probabilities; # 将列表中的所有元素相乘

List::MoreUtils

all/any/notall/none { <condition> } @list

# @list 中有任意一个元素有定义
print "At least one value undefined" if any { !defined($_) } @list;

# @list 中所有的元素都有定义
print "All items defined" if all { defined($_) } @list;

# @list 中没有元素被定义,它是 any 的反义
print "No value defined" if none { defined($_) } @list;

# @list 中至少有一个元素没定义,它是 all 的反义
print "Not all values defined" if notall { defined($_) } @list;

first_index { <condition> } @list

返回第一个满足条件的列表索引号。last_index 返回最后一个满足的索引号。没有找到满足的都返回 -1
my @list = (1, 4, 3, 2, 4, 6);
printf "item with index %i in list is 4", firstidx { $_ == 4 } @list;
__END__
item with index 1 in list is 4

apply { <transform> } @list

对于每个 @list 中的元素执行 transform, 然后在列表环境下返回改变后的列表,在标量环境下返回最后一个值。
它与 map 有点类似,但是 apply 不改变原来 @list 的值。
my @list = (1 .. 4);
my @mult = apply { $_ *= 2 } @list;
print "\@list = @list\n";
print "\@mult = @mult\n";
__END__
@list = 1 2 3 4
@mult = 2 4 6 8
my @nice_words = apply { s/$EXPLETIVE/[DELETED]/gxms } @words;

# 这面的这句如果用 map 写的话
my @nice_words
    = map {
          my $copy = $_;
          $copy =~ s/$EXPLETIVE/[DELETED]/gxms;
          $copy;
      } @words;

after/before BLOCK LIST

返回满足 BLOCK 后面或前面的列表元素。如
@x = after { $_ % 5 == 0 } (1..9);    # returns 6, 7, 8, 9

而 after_incl/before_incl 也包括满足 BLOCK 的元素,如上面就会多一个 5

pairwise BLOCK ARRAY1 ARRAY2

ARRAY1 ARRAY2 对应平行的元素(设置成 $a 和 $b)做 BLOCK 后返回。如
@a = (1 .. 5);
@b = (11 .. 15);
@x = pairwise { $a + $b } @a, @b;	# returns 12, 14, 16, 18, 20

# mesh with pairwise
@a = qw/a b c/;
@b = qw/1 2 3/;
@x = pairwise { ($a, $b) } @a, @b;	# returns a, 1, b, 2, c, 3

如果数组元素个数不同的话,自己试验下。
注意这里的 $a 和 $b 是绑定数组元素,所以如果对 $a/$b 进行更改的话会对应修改数组。

zip/mesh @array1, @array2, ...

跟 Perl 6 中一样。不同数组依次取一个,然后循环。
@x = qw/a b c d/;
@y = qw/1 2 3 4/;
@z = zip @x, @y;	    # returns a, 1, b, 2, c, 3, d, 4

uniq @list

uniq 是 unique 的缩写,独一无二的。
my @x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 1 2 3 5 4
my $x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 5 不同的个数

Others

  • insert_after BLOCK VALUE LIST / 在满足 BLOCK 的列表元素后插入 VALUE
  • insert_after_string STRING VALUE LIST / 在等于 STRING 的列表元素后插入 VALUE
  • indexes BLOCK LIST / 与 first_index 不同,它返回一个由所有的索引号组成的列表

不想写太多了。详细的查阅文档。其实不是 Perl 不够强大,只是你没发现而已。



blog comments powered by Disqus