@kyanny's blog

My thoughts, my life. Views/opinions are my own.

再帰?は難しい

以下のようなことがしたかったけど、うまくいきませんでした。

my @categories;
my @links;
sub extract_bookmark_recursively {
    my $bookmarks = Netscape::Bookmarks->new($file);
    for my $bookmark (@{$bookmarks->elements}) {
        if ($bookmark->isa("Netscape::Bookmarks::Category")) {
            push @categories, $bookmark->title;
            extract_bookmark_recursively($bookmark);
        }
        elsif ($bookmark->isa("Netscape::Bookmarks::Link")) {
            push @links, { bookmark => $bookmark, categories => \@categories };
        }
    }
    @categories = ();
}

Netscape::Bookmarks というモジュールでネットスケープのブックマーク形式のファイルをパースして帰ってくるオブジェクトは elements というメソッドで Netscape::Bookmarks::Category もしくは Netscape::Bookmarks::Link のオブジェクトの配列のリファレンスを返すのだけど、それを Link のみのフラットなデータ構造に直したい。のだけど category を捨てたくはないのでそれはうまく持っていたい。ネストはどれくらい深くなるかわからないので、ループを重ねてもダメだなとおもい再帰呼び出しをしてみたけど、肝心のでかいハッシュリファレンスを作るところで煮詰まってしまいました。これでうまくいってるように見えるってことは、どういう風に再帰呼び出しされてるかが追えてないってことでしょうね。あーあわかんね。

・・・やっぱりこれでうまくいかないってことはないだろうと思ってやり直してみたら、ちゃんと動いてました。どうやら呼び出し側のコードがまずかったようで、

sub foo {
    my @links;
    extract_bookmark_recursively($bookmarks);
    print Dumper(\@links);

という風にしていたらダメでうなっていたのですが、 sub foo の中じゃなくて外に our @links; と宣言したらとれました。外で宣言しなくてはならないのがどうにも気持ちが悪い。でも、しょうがないんでしょうね、 Perl を使う以上は。