Perl で関数内に関数を定義する ― 2021年12月20日 21時08分
この記事は Perl アドベントカレンダーの 20 日目の分です。
Perl コードを書いていて、関数内で関数を定義したいと思ったことはありませんか? 普通に sub foo { ... }
の中に sub bar { ... }
を書けばよいのでは思われるかもしれませんが、それだと関数が局所的にならず外部に露出してしまいます。
package MyPackage {
sub foo {
sub bar { 42 }
return bar();
}
}
# foo 関数の外部からも bar 関数を呼び出せる。
say MyPackage::bar(); # => 42
無名関数のコードリファレンスを使うこともできますが、見た目がちょっと煩雑ですね。
package MyPackage {
sub foo {
my $bar = sub { 42 };
return $bar->();
}
}
そこで lexical subroutines の出番です。my sub foo { ... }
または state sub foo { ... }
と書くことで、局所的な関数を定義できます。Perl 5.18 で試験的に導入された機能で、Perl 5.26 から本採用となり警告なしで使えるようになりました。
package MyPackage {
sub foo {
my sub bar { 42 }
return bar();
}
}
# foo 関数の外部からは bar 関数を呼び出せない。
say MyPackage::bar(); # => Undefined subroutine &MyPackage::bar called
lexical subroutines は sort
関数に渡すこともできます。
my sub compare { $b <=> $a }
my $array_1 = [ sort compare 1, 8, 2, 3, 5 ];
my $array_2 = [ sort compare 4, 7, 6, 0, 9 ];
say @$array_1; # => 85321
say @$array_2; # => 97640
注意点として、Perl の lint である Perl-Critic には、バージョン 1.140 時点で lexical subroutines に誤った警告を出してしまうという問題があります。
- ProhibitBuiltinHomonyms misinterprets "my sub" subroutines · Issue #955 · Perl-Critic/Perl-Critic
- Support for local subs with `my sub` · Issue #946 · Perl-Critic/Perl-Critic
筆者はいずれの問題に対しても修正 pull request を提出しています。Perl-Critic の誤検知がなくなり、気兼ねなく lexical subroutines が使えるようになるとよいですね。
HTML の img 要素と image タグ ― 2021年12月20日 23時40分
この記事は HTML アドベントカレンダーの 20 日目の分、兼 JavaScript アドベントカレンダーの 20 日目の分です。
HTML のタグといえば、要素の開始位置、終了位置、そして属性を指定する記述のことですね。開始タグは小なり記号 (<
) の後に要素名が続きます。しかしながら、タグに既述した名前とは別の名前の要素が生成される場合があります。
以下の JavaScript コードを実行すると、JavaScript コンソールには (IMAGE
ではなく) IMG
と出力されます。タグに記述された名前は image
なのに、img
要素が生成されているのです。
const div = document.createElement('div');
div.innerHTML = '<image src="" alt="">';
console.log(div.firstChild.tagName); // => "IMG"
実はこれは HTML のパース処理における例外的な扱いで、開始タグの名前が image
のとき、内部的にはパースエラーとしつつ名前を img
に読み替えることになっています。Web 製作者の記述ミスを救済しようとする慈悲の心の現れですね。
あくまでも HTML のパース処理における例外なので、JavaScript で document.createElement
メソッドを使って要素を生成するときには適用されません。以下の例では "[object HTMLUnknownElement]"
という文字列が出力されるはずです。(しかし Firefox では "[object HTMLElement]"
という文字列が出力されます。)
const image = document.createElement('image');
console.log(image.toString());
最近のコメント