Все задачи

Имя, размер, содержание

16 Aug 2013

Программист написал функцию, которая должна читать файл и возвращать его содержимое и размер.

use File::Slurp;

# Получает имя файла, 
# читает файл и его метаданные,
# возвращает ссылку на хеш { filename => '...', content => '...', size => NNN }.
# Если файл не существует, content и size равны undef
sub read_file_with_metadata 
{   
    my ($filename) = @_;
    my @stat = stat $filename;

    return {
        filename => $filename,
        content => eval {scalar read_file($filename)},
        size => $stat[7],
    };
}

И все бы хорошо, но иногда в поле content оказываются совершенно неправильные значения.

Пример кода можно скачать и поотлаживаться локально.

Подсказка

Показать

Это происходит, когда функция получает имя несуществующего файла.

Подсказка-2

Показать

Результат в этом случае получается такой:

{ 
    '' => undef,
    filename => '<nonexistent_file>',
    content => 'size'
};

Разоблачение

Показать

Проблема в eval, которым обернут вызов read_file. Если код внутри eval выполняет die, то eval возвращает undef в скалярном контексте и пустой список в списковом контексте.

Таким образом, если файл не существует, возвращаемое значение функции превращается в

{
    filename => $filename,
    content => 'size',
    $stat[7],
}

, а это, конечно, не то, что задумывалось.

Кстати, если бы программист использовал прагму warnings, он мог бы заметить предупреждение
Odd number of elements in anonymous hash

Короткое исправление могло бы быть таким:

-        content => eval {scalar read_file($filename)},
+        content => scalar eval {scalar read_file($filename)},

Также см. http://perldoc.perl.org/functions/eval.html