この記事は、Perl Advent Calendar 2021 の24日目の記事です。 23日目は @hitode909 で「リポジトリ内のソースコードを機械的にリファクタリングし続けるスクリプトを作る」でした。
今日はちょっと前から使えるようになってたけど滅多にお世話になることのない、「文字列用ビット操作演算子」を触ってみたというお話です。
特に断りのない限り 2021-12-24 現在の最新安定版 Perl 5.34.0 で動作確認をしています。
旧来のビット演算子
Perl の多くの演算子には「数値用」と「文字列用」があります。
例えば比較演算子であれば ==
, !=
は数値用、 eq
, ne
は文字列用といった具合です。
しかし、ビット操作用の演算子だけには、なぜかその区別がなかったのです。
以下は perlop Bitwise String Operators から引っ張ってきた例です。
|
は論理和を求める演算子ですが、両辺の型に応じて結果が変わります。
use warnings;
use strict;
use feature qw/say/;
say 150 | 105; # = 255 (0x96 | 0x69 = 0xFF)
say '150' | 105; # = 255
say 150 | '105'; # = 255
say '150' | '105'; # = 文字列の '155' (ASCII)
結果:
255
255
255
155
最後の文字列同士の計算だけ結果が違うのは、文字列同士の場合はバイト毎に論理和の計算が行われるためです。
0x31 ('1') | 0x31 ('1') = 0x31 ('1')
0x35 ('5') | 0x30 ('0') = 0x31 ('5')
0x30 ('0') | 0x35 ('5') = 0x31 ('5')
このちょっと面白い(面白くはない)挙動については、Perl の JSON::PP での数値の扱いが変わっていた件でも簡単に触れました。
bitwise feature
「これはちょっと分かりにくいよね」ということで Perl 5.22 から「数値用」「文字列用」の演算子を分けることができるようになりました。
後方互換性のためにデフォルトでは無効化されているので、 feature
プラグマで明示的に有効化する必要があります。
bitwise
を有効化すると、今までのビット演算子は「数値用」になります。
両辺が両方とも文字列であった場合も、数値に変換されてから演算されます。
use warnings;
use strict;
use feature qw/say bitwise/;
say 150 | 105; # = 255 (0x96 | 0x69 is 0xFF)
say '150' | 105; # = 255
say 150 | '105'; # = 255
say '150' | '105'; # = 255
結果:
255
255
255
255
「文字列用」にはドット付きの &. |. ^. ~.
を使います。
use warnings;
use strict;
use feature qw/say bitwise/;
say 150 |. 105; # = '155'
say '150' |. 105; # = '155'
say 150 |.'105'; # = '155'
say '150' |.'105'; # = '155'
結果:
155
155
155
155
Perl 5.22 から Perl 5.26 までは「実験的機能」扱いなので警告がでます。 Perl 5.28 からは警告なしで使えます。
feature bundle 経由で使ってみる
Perl 5.28 から正式な機能として扱われるようになったので、 最小バージョンを明示することでも有効化できます。
use warnings;
use v5.28; # Perl 5.28 以降で使える機能を有効化
# 以下は use v5.28 に含まれるので省略可
# use strict;
# use feature qw/say bitwise/;
say 150 |. 105; # = '155'
say '150' |. 105; # = '155'
say 150 |.'105'; # = '155'
say '150' |.'105'; # = '155'
有効化される機能は say
bitwise
だけではありません。
完全な一覧は FEATURE BUNDLES を参照してください。
まとめ
- 文字列専用ビット演算子
&. |. ^. ~.
を使ってみました - Perl 5.28 から正式に採用
use v5.28
oruse feature 'bitwise'
で使えます
正直こんな演算子が追加されていたなんて、最近まで知らなかった・・・。
明日25日は @karupanerura で「Perlと型とコンテキスト」です。お楽しみに!