
お世話になります。
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で質問しましょう!
似たような質問が見つかりました
- Windows 10 数年前からWindows10 の Update ができないです。なぜですか? 7 2022/11/09 06:03
- Perl Perl の外部モジュールの利用方法 3 2022/07/10 18:34
- Perl Perlのエラーについてご教授ください。初心者です。 CGIを別サーバに移したところ、Perlのバー 5 2023/05/31 10:48
- プリンタ・スキャナー キャノンmp490プリンター【エラー番号5400】で【プリンタートラブルが発生しました。電源を入れ直 2 2023/07/24 17:45
- CGI -T(汚染モード)でメールが送れません 1 2022/06/12 14:11
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- Excel(エクセル) 【マクロ】エラーが発生⇒実行時エラー58既に同名のファイルが存在 5 2022/08/31 10:03
- Windows 10 Windows Updateが動作しません 7 2022/08/12 16:26
- Visual Basic(VBA) VBAでのMATCH関数 3 2022/10/17 19:06
- Visual Basic(VBA) excel vbaでselenium basic 3 2022/10/02 12:35
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「フォームメールの値の引渡し...
-
Perlのエラー検出法など
-
perl if文 助けて~
-
VBSがコンパイルエラーになりま...
-
WebClientの文字列送信にてエラー
-
英字のみを検索する正規表現に...
-
python 3を使えるようになりたい
-
perlをバージョンアップしたら...
-
ショッピングカートのカスタマイズ
-
メールアドレスについて
-
例外処理のフローチャートの記...
-
「デバイスは PRN を初期化でき...
-
Perlのサブルーチンで連想配列...
-
javascript の使用は可能か
-
モジュールは設置するだけでは...
-
構文チェックについて
-
plalaで起こるリンクの不可解な...
-
記号の組み合わせのテキスト文...
-
モジュールからフォームのボタ...
-
CPANの環境、インストール設定
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBSがコンパイルエラーになりま...
-
教えて下さい。
-
perlをバージョンアップしたら...
-
erf(x)とerfc(x)のカタカナ読み...
-
VBからブラウザの表示状態(リ...
-
WebClientの文字列送信にてエラー
-
エラー画面の制御?
-
エクセルで指定した行範囲を別...
-
Pythonプログラミングでエラー
-
powershellで引数受け取り時に...
-
w3cの検証エラー?
-
POSTで送信するとエラーになる
-
script headers って?
-
Excelマクロでセルに値が入力さ...
-
ホームページがgoogle検索結果...
-
perl ver5.24.0 x68版で、requi...
-
pingサーバーに更新pingを送信...
-
sprintfで0ならスペースにしたい
-
プログラミング?を作りたいです
-
%stderr%の値が何をさしているのか
おすすめ情報