Perl Hackers Hub

第16回 Perl内部構造の深遠に迫る(1)

この記事を読むのに必要な時間:およそ 5 分

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回はgfxこと藤吾郎さんで,テーマはPerlの内部構造です。

内部構造を覗く

Perlで開発をしていると,ときどきわかりにくい現象に遭遇することがあります。たとえば,あるデータをJSONJavaScript Object Notationにシリアライズするとき,数値としてシリアライズしてほしい値が文字列としてシリアライズされてしまう。あるいは,エンコーディングが正しいはずなのに文字化けが起きる。こんなときは,思いきってPerlの内部構造を覗くことで,何が起きているかを突き止めることができます。

本稿では,Perlの内部構造について解説します。言及するperlはバージョン5.16.0(2012年5月21日リリース)です。また,ターミナルのエンコーディングはUTF-8を想定しています。なお,Perl処理系はC言語で書かれているのですが,本稿においてはC言語の知識は必須ではありません。

perl──Perl処理系の実装

本題の前に,Perl処理系について少し触れておきます。Perl言語の処理系は事実上1つしかなく,この実装はすべて小文字で「perl」と書きます。本稿でも以降perlと書くときはこの実装のことを指します。perlは前述したようにCで書かれているソフトウェアです。大量のマクロによって慣れないと非常にわかりにくいのですが,一つ一つ読み解けば理解はできます。

もっとも,本稿ではソースコードをほとんど参照しませんし,実際のデバッグでもソースコードを参照しなければならないケースはまれです。それでも,知識として内部構造を知っていると,内部構造を調べるツールを利用して問題を追っていくことができるのです。

SV構造体とDevel::Peekの読み方

さて,最初のテーマはSV構造体注1です。SV構造体とは,Perlの値の実体です。Perlの値はほとんどの場合,中身が数値であるとか文字列であるということを意識せずに使えますが,それはSV構造体がそのように定義されているからです。つまりSV構造体を調べれば,perlの値の挙動がすべてわかるというわけです。

注1)
構造体とは,Cのデータ型の一種で,Perlのハッシュリファレンスのように名前と値のペア複数からなるデータです。

JSONシリアライズ問題

SV構造体を調べる前に,まずSV構造体の実装に起因した問題を追ってみましょう。

リスト1のコードを実行してみます。これは,JSON::PPモジュール注2を使ってPerlのデータ構造をJSONにシリアライズするコードです。

リスト1 buggy-json-serialize.pl

use strict;
use warnings;
use feature 'say';
use JSON::PP qw(encode_json);
$| = 1; # autoflush

my %data = (
    answer => 42,
);

say "the answer: $data{answer}"; # (a)

say encode_json(\%data);
# 実行結果:
# The answer: 42
# {"answer":"42"}

$| = 1はSTDOUTのautoushを有効にするもの。これがないと,STDOUTに出力するsay()とSTDERRに出力するDump()が正しい順番で表示されないことがあるため行っている

実行結果を見ると,JSONにシリアライズした"answer"の値が文字列の"42"になっています。JSONは数値と文字列を区別するフォーマットですから,数値として入れたものは数値としてシリアライズされなければ意図したとおりではありません。(a)の行をコメントアウトすると意図どおり数値にシリアライズされます。この問題はWeb APIのレスポンスとしてJSONを返すアプリケーションで起こりがちです。一般的には,数値として出力すべきものは0 +$data{answer}などとして確実に数値にしてからデータ構造を作り,その後すぐにシリアライズすることで回避できるとされています。

なぜこのような問題が起きるのでしょうか。「確実に数値にしてから」とはどういう意味なのでしょうか。そもそもPerlの値に数値や文字列といった区別はあるのでしょうか。あるとしたらどのように区別されるのでしょうか。この疑問に答えるために,SV構造体を調べる必要があるのです。

注2)
JSON::PPモジュールはPerl v5.14.0から標準モジュールです。

著者プロフィール

藤吾郎(ふじごろう)

ソフトウェアエンジニア。DeNAでスマートフォンアプリのミドルウェアやJSXなどを開発している。Perlとの付き合いも長く,Shibuya.pmやYAPC::Asiaにスピーカーとして参加もしている。

ブログ:http://d.hatena.ne.jp/gfx/

ハンドルネーム:gfx

コメント

コメントの記入