autobox - 使 Perl 5 程式耳目一新

作者:   發佈於: ,更新於:

在一些近代所發明的輕量語言裡,有這種語法:


# 2
["Hello", "World"].length

# "Hello World"
["Hello", "World"].join(" ")

["Hello", "World"] 表示一個陣列,而 .length 則是取前述陣列的屬性。 甚至也可以直接對此陣列調用陣列的方法 .join(" ")

這種可以將程式中原生資料型別 (primitive data type) 直接當成是物件來使用 的概念,稱為 autoboxing。在 Ruby 與 Javascript 的程式語言中,已經很簡明地直接成為其設計的一部份了。

在 Perl 5 中,則可以使用 autobox.pm 模組來輕易完成。

use autobox::Core;
"Hello World"->say;

當然不只是字面值可以做為物件來用,一般的純量變數也行:

use autobox::Core;
my $word = "Hello World";
$word->say();

光是這樣也許看不出倒底好在哪裡,畢竟只是把句子倒過來寫而已 (原本寫 say "Hello world",後來寫成 "Hello world"->say()),寫長一點的效果就明顯許多:


use autobox::Core;
my $word = "hello world";

$word->split(" ")            # ("hello", "world")
    ->map(sub { ucfirst })   # ("Hello", "World")
    ->join(" ")              # "Hello World"
    ->say;                   # say it!

這種主詞在前,後綴許多動詞的寫法,讀起來比以下一般用 Perl 5 會採用的寫法好讀一些:


say
join " ",                    # "Hello World"
map { ucfirst }              # ("Hello", "World")
split(" ", $word);           # ("hello", "world")

主要的原因在於閱讀的次序,前段程式碼要依照以下的順序讀:


say                          # 4
join " ",                    # 3
map { ucfirst }              # 2
split(" ", $word);           # 1

而改用後綴的寫法,閱讀順序如下:


$word->split(" ")            # 1
    ->map(sub { ucfirst })   # 2
    ->join(" ")              # 3
    ->say;                   # 4

可讀性顯然大幅提升。

想要立刻開始使用的讀者,請安裝 CPAN 上的 autobox::Core,與 autobox 雖分屬兩不同的散佈檔中, 但 autobox::Core 替原生資料型別提供的方法更加的完善、好用。autobox 提 供了基本能力,而 autobox::Core 則使其更加的實用。程式碼中只要 use autobox::Core 即可。

註一:

或許有人會認為我用了 map 所以才使得程式碼要倒過來讀,但不用 map 的寫法如下:


my @tmp = split(" ", $word); # 1, @tmp  ==> ("hello", "world")
for(@tmp) { $_ = ucfirst }   # 2, @tmp  ==> ("Hello", "World")
$word = join(" ", @tmp);     # 3, $word ==> "Hello World"
say $word;                   # 4

順序是好的,但卻需要另一個變數來暫存結果,使得這四列程式碼中,$word@tmp 這兩個變數都使用了好幾次。這反而使其成為了最難閱讀的寫法之一。

註二:

這篇文章舉的例子完全是為了說明而造出來的,如果真的只是要把 "hello world" 轉寫成字母首字大寫,最快的方式是:

$word =~ tr/hw/HW/;

但這種解法也只僅對此特例最快而已 :)