
お世話になります。
Ubuntuのアップデート通知がうるさいので、このたび重い腰を上げて22.04.1 LTSにアップデートしました。
これにより自動的にPerlも5.34に上がったようです。
そしたら今まで正常に動いていたperlスクリプトがエラーになってしまいました。
同じエラーを再現するための必要最小限のコードを書き下ろしました。
#!/usr/bin/perl -w
use strict;
my($v, @a) = 0;
@{0 < $v ? $a[0] : $a[1]}{'a', 'b'} = (0, 1)
見にくくてスミマセンが、配列の1要素にハッシュへのリファレンスを代入しています。
これを実行すると、
Can't use an undefined value as a HASH reference at ./try line 4.
とのエラーが発生してしまいます。
しかし、バージョンアップする前(perl5.30か)では、エラーは発生しませんでしたので、少なくともperl5.30では、これは正しいコードと認識しています。
5.30から5.34までの0.04の間にどのような変更があったのでしょうか。
ちなみに変数$vを使わず直接0 < 0と書いたり、条件演算子の一方を配列でなく0 < $v ? 0 : $a[1]のようにリテラル値にすると、なぜかエラーは発生せず、ますます良く分かりません。
エラーが発生しないように、コードを書き替える事は可能ですが、できれば、この挙動の解説をお願いします。
No.3ベストアンサー
- 回答日時:
「先生」と呼ばれるほどの何者でもないんだけど, 確かに数が多いとどうしようか困るなぁ. 自分だったら... 「そういうハッシュへのリファレンス」を返すサブルーチンを作るかなぁ. 例えば
sub 「そういうハッシュを作るぜ」
{
my %h;
@h{'a', ..., 'f'} = @_;
\%h;
}
ってサブルーチンを作ってそれを
(0 < $v ? $a[0] : $a[1]) = 「そういうハッシュを作るぜ」(@$_);
みたいに呼び出す, みたいな.
この質問文の例のように「同じ配列の異なる要素に入れる」というなら
@{$a[0 < $v ? 0 : 1]}{'a', 'b'} = (0, 1);
のようにもできるんだけどね....
ありがとうございます。
サブルーチンを作ったらうまくいきました。
まあ、本件ではたかだか6件のリストを代入するだけですので、サブルーチンを作るほどの件数ではないですかね。
となると、やはり最初に教わった無名ハッシュ生成子を使って1個1個代入するのが、ここでは最もスマートですかね。
@{$a[0 < $v ? 0 : 1]}{'a', 'b'} = (0, 1)
同じ配列なら、このような巧妙な書き方もできるのですね。
この書き方ならエラーは発生しませんでしたし、よりタイプが少なくて好きです。
しかし残念な事に本番では同じ配列ではないため、この書き方はあきらめます。
No.2
- 回答日時:
これを書いて (打って) いる時点での Perl の最新バージョンは 5.36.0 なんだけどそれではチェックしてないですよ~と逃げを打っておいて, と.
手元の 5.26.3 と 5.32.1 で試したところ, 前者ではうまく動いたけど後者はアウトだった. なので, 質問文の「少なくともperl5.30では、これは正しいコードと認識しています」が正しいとすれば 5.30 と 5.32.1 の間のどこかで非互換な修正が入ったものと思われる.
とはいえドキュメントを見た限りでは探せなかったのでもうちょっと掘ってみたんだけど, なんとなく「意図しない非互換な修正」もっといえば「つい間違って突っ込んじゃったバグ」のような気がする. 少なくとも手元の 5.32.1 では質問文の
@{0 < $v ? $a[0] : $a[1]}{'a', 'b'} = (0, 1);
の代わりに
@{0 <= $v ? $a[0] : $a[1]}{'a', 'b'} = (0, 1);
とすると動いてしまっている. でも, 「上はダメで下は OK」という「合理的な理由」があるようには思えない.
ただしどこでなにがどうおかしくなっているのかまでは追求できず... というか, 個人的には
@{0 < $v ? $a[0] : $a[1]}{'a', 'b'} = (0, 1);
と同じ動作をするにしても
(0 < $v ? $a[0] : $a[1]) = { a => 0, b => 1 };
なり
$a[0 < $v ? 0 : 1] = { a => 0, b => 1 };
なりと書いてしまうので追求するモチベーションがない.
なお autovivification をつぶすとは考えにくい>#1.
貴重なお時間を割いていただき感激です。
当人の私ですら最新を入れるモチベは無いので当然です。
ウィザード級の腕を持ってしても無理と回答があると、私は満足して前進できるのです。
しかし本番は、リストがもう少し多く(とは言え6個ですが)、
@{0 < $v ? $a[0] : $a[1]}{'a', 'b', 'c', 'd', 'e', 'f'} = @$_
このように書いて、少ないタイプで代入できて気持ちいと思っていたところです。
この場合、先生はどう書きますか。
私がいつも便利だと思ってすすんで使っていた機能はautovivificationと言うのですね。
No.1
- 回答日時:
あまり詳しくないので推測となりますが...
リファレンスが未定義のまま使っているのは、そもそもバグですので直しましょう
https://perldoc.jp/docs/perl/5.28.0/perldiag.pod
> Can't use an undefined value as %s reference
> (F) ハードリファレンスやシンボリックリファレンスとして使用する値は、 定義済みの値でなければなりません。 潜伏中のエラーを引きずり出す助けとなります。
ご提示の場合だと @a の初期化にて、各項目に HASH リファレンスを代入しましょう
例) my @a = ( {}, {} );
5.36 に以下の変更が入っていましたので、
5.34 でも診断精度が上がった結果として摘出されたのではないでしょうか
https://perldoc.jp/docs/perl/5.36.0/perl5360delt …
> perl5360delta - perl v5.36.0 での変更点
> 新しいエラー
> Can't modify %s in %s (for scalar assignment to undef)
> undef = $foo; のように、undef にスカラを代入しようとしました ...
余談)
これまで未定義でも動いていたのは自動補正してくれたからですが、このような補正に頼っていてはいけないという -w オプションからの忠告なのでしょう
ご教授に従い、あらかじめ空のハッシュへのリファレンスを定義したら、エラーが発生しなくなりました。
しかし、先のコードをさらに簡略化して、
#!/usr/bin/perl -w
use strict;
my(@a);
@{$a[0]}{'a', 'b'} = (0, 1)
とすると、あらかじめ定義していないのに、エラーは発生しません。
不思議です。
また余談について、もしやと思い、試してみましたが、本件は-wオプションの有無にかかわらず、エラーになるようです。
ついでにuse strict;も無くしてみましたが、エラーはなくなりませんでした。
しかし未定義でも、書き方によってエラーになったり、ならなかったりするので、いまいち納得いかないのです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
教えて下さい。
-
VBSがコンパイルエラーになりま...
-
データベースが返すエラー文字...
-
例外処理のフローチャートの記...
-
Excel VBAで、ユーザーフォーム...
-
同一筐体におけるPerlの複数バ...
-
エクセルVBA クラスモジュール...
-
VBAで別モジュールへの変数の受...
-
VBでグローバル変数を宣言するには
-
Cからシェルを起動し返り値をハ...
-
フォーム名一覧の取得
-
VBAProjectのモジュ...
-
標準モジュールを削除したい。(...
-
モジュールからフォームのボタ...
-
VBAで「メモリが不足しています」
-
pythonでファイル移動できません。
-
本当にPublicな変数(配列で)
-
Perlでモジュールをインストー...
-
エクセルVBAでシートモジュール...
-
Perlの処理待ちコマンド
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBSがコンパイルエラーになりま...
-
perlをバージョンアップしたら...
-
教えて下さい。
-
Pythonプログラミングでエラー
-
WebClientの文字列送信にてエラー
-
「フォームメールの値の引渡し...
-
perl if文 助けて~
-
8進数文字列を10進数の数値に...
-
【python】requestsでdataとし...
-
メールアドレスについて
-
Perlのエラー検出法など
-
erf(x)とerfc(x)のカタカナ読み...
-
英字のみを検索する正規表現に...
-
ラズパイ4からGmailへの...
-
入力必須フォーム→ エラーのペ...
-
データベースが返すエラー文字...
-
python 3を使えるようになりたい
-
CGIの接続エラー
-
構文エラーのある行番号を知りたい
-
ショッピングカートのカスタマイズ
おすすめ情報