読者です 読者をやめる 読者になる 読者になる

tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

perlのundefの挙動2(return;でhashが壊れる

perlのundefの挙動1(関数でなにも返さないとhashが壊れたりとか
で、return;の挙動がundefと違うことを確認しましたが
これを使うとhashが壊れるっていう検証です

前回と同じくundef的なものを返す関数をいくつか定義

# return;のパターン(ifはあまり意味ない)
sub hoge
{
  return if(!&piyo);
}

# return undef;のパターン
sub piyo
{
  return undef;
}

# return;の関数をそのまま返却
sub func
{
  &hoge;
}

# return;の関数を一度スカラーで受け取ってから返却
sub func2
{
  my $hoge = &hoge;
  $hoge;
}

hashのvalueに入れてみるテスト

出力して検証
warn "[case1]\n";
my $hash = {
  key1 => &func,
  key2 => 'aiueo',
};
warn Dumper($hash);

warn "[case2]\n";
my $hash = {
  key1 => &func2,
  key2 => 'aiueo',
};
warn Dumper($hash);

warn "\n";
warn "[case3]\n";
$hash = undef;
$hash = {
  key1 => &hoge,
  key2 => 'aiueo',
};
warn Dumper($hash);

warn "\n";
warn "[case4]\n";
$hash = undef;
$hash = {
  key1 => &piyo,
  key2 => 'aiueo',
};
warn Dumper($hash);

warn "\n";
warn "[case5]\n";
$hash = undef;
my $val = &func;
$hash = {
  key1 => $val,
  key2 => 'aiueo',
};
warn Dumper($hash);
出力結果
[case1]
Odd number of elements in anonymous hash at undef_test.pl line 197,  line 1.
{
  'aiueo' => undef,
  'key1' => 'key2'
}
[case2]
{
  'key1' => undef,
  'key2' => 'aiueo'
}

[case3]
Odd number of elements in anonymous hash at undef_test.pl line 213,  line 1.
{
  'aiueo' => undef,
  'key1' => 'key2'
}

[case4]
{
  'key1' => undef,
  'key2' => 'aiueo'
}

[case5]
{
  'key1' => undef,
  'key2' => 'aiueo'
}
ってことで

前回と同じで、[case1]の定義関数funcがおかしいです。
今回の場合だと[case1]のfuncをhashのvalueにそのまま入れると
ぶっ壊れて大変なことになります。

これは下記のようにhashの定義をリストのように書くことができることからもわかりますが
val1がundef(未定義な値)でもなく、未定義でもなんでもなく存在すらしないということで、ズレてしまうことから起こるようです。

# リストのように定義できる
my %hash = (key1, val1, key2, val2);

# val1を今回のfuncに置き換えると。。。
my %hash = (key1, func, key2, val2);

# 存在しないものを指定したため1つづれるイメージ
my %hash = (key1, key2, val2, undef);

これでハマるパターン

ちなみに自分のところでは下記のようなテンプレートへのアサイン時におかしくなってかなりハマりました

$self->tmpl->param("key1" => func);
$self->tmpl->param("key2" => 'anyvalue');

単一のhashであればまだわかりやすいんでしょうが、
このような書き方の際にfuncのせいでkey2がぶっ壊れると、key2がぶっ壊れる理由がかなり特定しずらくなります。
しかもkey1とkey2のアサインの間に違う処理があったりなんかするともう。。。。汗

考察

なので

    • 関数でreturn;と書く場合、しっかりとスカラーで受け取ってから使う
    • return;と書かない。(return undef;と明記)

ってことですかね。
個人的にはreturn undef;と明記するほうが好きかな。