前回の
移植時に活用すべき機能
移植方針の目処が立ったら、
(2)
正規表現
Perlでは、
たとえば、Stringクラスのeach_インスタンスメソッドを呼び出すことで実現できます。
text.each_char do |ch|
    # chを使って処理する
endPerlでは、
for my $ch ($text =~ /./g) {
    # $chを使って処理する
}gフラグを付けた正規表現マッチは、
my @ch = 'abcd' =~ /./g;
# => ('a', 'b', 'c', 'd')配列を処理する関数・ライブラリ 
ある配列の各要素を加工した配列を作ったり、
[1, 2, 3].map { |x| x * 2 } # => [2, 4, 6]Perlの配列は、forループで要素をpushしていく方法と、mapやgrepといった配列を操作する組込み関数を使う方法が考えられます。
単純な処理であれば、twiceを、forループで各要素を2倍にしてpushする方法と、mapを使う方法とで実装した場合の速度を比較してみましょう。以下に、twice.と筆者の環境
twice.pl
use Benchmark qw(:all);
sub twice_map {
    return map { $_ * 2 } @_;
}
sub twice_push {
    my @ret;
    push @ret, $_ * 2 for @_;
    return @ret;
}
my $count = 100000;
my @input = (1..10000);
cmpthese($count, {
    twice_map => sub {
        twice_map(@input);
    },
    twice_push => sub {
        twice_push(@input);
    },
});% perl twice.pl
             Rate twice_push  twice_map
twice_push 1371/s         --       -48%
twice_map  2630/s         92%        --
mapを使うほうが、forループでpushしていくよりも2倍近く高速に処理できていることがわかります。
mapやgrepといった組込み関数よりも高度な処理を行いたい場合は、
移植時に注意すべきこと
せっかくライブラリをPerlに移植できても、
本節では、
文字コード
操作する対象の文字列を、
プログラミング言語によっては、utf8フラグの有無によって文字列であるかバイト列であるかが変わります。また、
たとえば、lengthの返す結果は、
use utf8;
my $x = '日本語'; # $xはUTF-8文字列
warn length $x; # => 3
{
    no utf8;
    my $y = '日本語'; # $yはバイト列
    warn length $y; # => 9
}Perlの文字列の内部表現や、utf8フラグについての詳細は、
YAMLライブラリの選定
YAML::Tiny、
YAML::Tinyはその名のとおり、
YAML::PPはYAML 1.
Twitter::Textの実装にあたっては、
関数がリファレンスを返すかどうか
Perlでは、
# 配列を返す場合
sub func1 {
    my @array;
    ...
    return @array;
}
# 配列リファレンスを返す場合
sub func2 {
    my $array = [];
    ...
    return $array;
}どちらを選択するにせよ、
配列そのものを返す場合
配列そのものを返す場合、map { bar($_) } func1()のように、
# baz()は値の組を返す関数
my ($foo, $bar) = baz();一方で、
# 配列そのものをネストさせることはできない
my @arr1 = (1, 2);
my @arr2 = (0, @arr1, 3);
# => (0, 1, 2, 3)
# bar()が(1, 2)という配列を返す場合、
# func('foo', 1, 2)と等価になる
func(foo => bar());配列リファレンスを返す場合
配列リファレンスを返す場合は、
# 配列リファレンスはネストできる
my $arr1 = [1, 2];
my $arr2 = [0, $arr1, 3];
# => [0, [1, 2], 3];
# bar()が[1, 2]という配列リファレンスを返す場合、
# func('foo', [1, 2])と等価になる
func(foo => bar());一方で、map { bar($_) } @{func2() }のようにデリファレンスが必要になります。また、undefを返してしまい、
sub func {
    # 配列リファレンスを初期化していない
    my $array;
    # 初期化せずにearly returnした場合、undefが返る
    return $array unless ...;
    ...
}真偽値
Perlでは、
- 未定義値undef
- 数値の0
- 文字列の'0'
- 空文字列''
文字列の'0'も偽値として扱われることに注意しましょう。デフォルトでは、
たとえば、func(foo => 'bar')のように、fooという名前付き引数に文字列を渡すか、$args{foo}のデフォルト値を補完しようとすると、'0'を引数に渡したとき、$args{foo}の値が意図せずデフォルト値になってしまいます。
sub func {
    my (%args) = @_;
    # 間違い
    $args{foo} ||= 'default value';
    ...
}次のように、exists組込み関数を使って$args{foo}が渡されているかどうかを判定してからデフォルト値を補完すると安全です。Perl 5.//=演算子を使うこともできます。
sub func {
    my (%args) = @_;
    # 正しい
    $args{foo} =
        exists $args{foo}
        ? $args{foo}
        : 'default value';
    # Perl 5.10以降なら次のようにも書ける
    $args{foo} //= 'default value';
    ...
}意図しない警告
use warningsしていると、undefを連結したときなどにエラーにならず警告が出力されます。警告の数が多いと、
移植したライブラリを使う際に、
use Test2::V0;
use Test2::Plugin::NoWarnings;
my $x = undef;
# 警告が出るのでテストが失敗する
print $x . ' is awesome';ただ、no warningsとすることで警告を無効化できます。
use warnings;
{
    no warnings 'utf8';
    # このスコープ内ではutf8に関する警告が無効化される
}
# スコープ外ではutf8に関する警告が出るまとめ
他言語で実装されたライブラリをPerlに移植する際の考え方や、
さて、
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/
定価1,628円
ISBN978-4-297-13000-8
- 特集1
 イミュータブルデータモデルで始める
 実践データモデリング
 業務の複雑さをシンプルに表現!
- 特集2
 いまはじめるFlutter
 iOS/Android両対応アプリを開発してみよう 
- 特集3
 作って学ぶWeb3
 ブロックチェーン、スマートコントラクト、 NFT 



