bonar note

京都のエンジニア bonar の技術的なことや技術的でない日常のブログです。

Use of uninitialized value の傾向と対策

テストスクリプトで Use of uninitialized value の valuewarning を出しまくってみました。

#!/usr/bin/perl

use strict;
use warnings;

my $str;    # undifined string
my %hash; # undifined hash

# Use of uninitialized value in pattern match
# Use of uninitialized value in substitution
$str =~ /a/; 

$str =~ s/a/b/g;

my $foo = 'hello';
$foo =~ s/hell/$str/;


# Use of uninitialized value in string eq
# (numeric eq, ==, lt, gt, ...)
if ($str eq 'a') {}
if ($str == 1) {}


# Use of uninitialized value in list assignment
my %a = ( $str => 1 );


# Use of uninitialized value in hash element
my $a = $hash{$str};

# Use of uninitialized value in concatenation
# Use of uninitialized value in sprintf
$a = "hello, " . $str;
$a = sprintf("hello, %s", $str);

# Use of uninitialized value in split
# Use of uninitialized value in join
my @a = split '-', $str;
      $a =join '-', ($str);

# empty hash key
my %id_name_table = (
    1 => 'foo',
    2 => 'bar',
    3 => 'buzz',
);
my $b = 'my name is ' . $id_name_table{4};

実行結果

Use of uninitialized value in pattern match (m//) at test.pl line 11.
Use of uninitialized value in substitution (s///) at test.pl line 13.
Use of uninitialized value in substitution (s///) at test.pl line 16.
Use of uninitialized value in string eq at test.pl line 21.
Use of uninitialized value in numeric eq (==) at test.pl line 22.
Use of uninitialized value in list assignment at test.pl line 26.
Use of uninitialized value in hash element at test.pl line 30.
Use of uninitialized value in concatenation (.) or string at test.pl line 34.
Use of uninitialized value in sprintf at test.pl line 35.
Use of uninitialized value in split at test.pl line 39.
Use of uninitialized value in join or string at test.pl line 40.
Use of uninitialized value in concatenation (.) or string at test.pl line 48.

そもそも値をセットするときに、

    my $str = get_some_value() || 'default value'

みたいに初期値がかならずセットされるようにすれば良い話なのですが、個人的によくやりがちなのが、ハッシュを受ける関数で特定のキーの値を正規表現でチェックする場合ですね。例えば、

sub somefunc {
    my %option = @_;
    
    if ($option{foo} =~ /^[a-z]$/) {
        # hoge hoge
    }
}
some_func(bar => 1);

みたいなやつですね。これでも動作的にはほとんどの場合ちゃんと動いてしまうんですよね。引数が任意の場合には

    if (exists $opt{foo} && defined $opt{foo}
        && $option{foo} =~ /^[a-z]$/) {
        # hoge hoge
    }

もしくはキーが出来ちゃってもいいなら

    if ($opt{foo} && $option{foo} =~ /^[a-z]$/) {
        # hoge hoge
    }

とかするようにしないとですね。かなり基本的なことですがちゃんと書く癖をつけないとなあ。。
ちょっと最近(仕事じゃないコードは特に)この辺に自分が無頓着だったなと反省したのでメモ。