Некоторые строковые значения (0, и ) определены, но (==undef)

В моем Perl-скрипте я использовал условие if ($a == undef), я думал, что это то же самое, что и if (not defined $a), где $a — это строка, прочитанная из CSV-файла. Однако я заметил, что некоторые строковые значения ("", " ", "0", "-0", "+0", "@", "a" и многие другие пробелы и специальные символы) определены, но также и undef. Если undef предназначен только для числовых значений, он должен передавать "0", "+0" и "-0". Кто-нибудь может объяснить? Теперь я понимаю, что не должен использовать if ($a == undef) вместо if (not defined $a).

Мой тестовый код:

@a_array = ("-1", "-0", "0", "+0", "1", "", " ", "@", "a", "\$", "-");
undef $a;
test_a();

foreach $a (@a_array) {
    $len_a = length($a);
    test_a();
}

sub test_a {
    if (defined $a) { print "a = $a is defined;  "} else {print "a = $a not defined; "}; 
    if ($a == undef) { print "a = $a (== undef);  "} else {print "a = $a (!= undef); "}; 
    if (length($a) > 0){ print "length of a is $len_a > 0 \n"} else {print "length of a is $len_a !> 0 \n"};
}

person Douglas    schedule 06.02.2020    source источник
comment
Всегда use strict; use warnings;. Не используйте в качестве примера $a, рассмотрите $x и $y.   -  person Grinnz    schedule 07.02.2020
comment
Всегда передавайте сабвуферам все, что им нужно, никогда не полагайтесь на то, что сабвуфер увидит значения извне. Так что test_a sub должен принимать $a в качестве аргумента (просто назван лучше).   -  person zdim    schedule 07.02.2020
comment
Документация для defined дает хорошее объяснение его назначения. undef — это отдельная сущность, отличная от 0, '' или чего-то еще.   -  person Polar Bear    schedule 07.02.2020


Ответы (1)


В Perl есть два оператора равенства: == и eq. == проверяет, равна ли числовая форма каждого значения. eq проверяет, является ли строковая форма каждого значения лексикографически равной. undef не является строкой или числом, и если используется как строка, она эквивалентна пустой строке, если используется как число, она эквивалентна 0 (как пустая строка и любая строка, которая не начинается с чего-либо). похоже на число). Обычно вы получаете предупреждения, когда это происходит.

Для проверки на undef не нужно проводить проверку эквивалентности: используйте функцию defined. Только если он определен, он может иметь значимое строковое или числовое значение, и вы можете выполнять последующие тесты.

Функция length возвращает undef при передаче undef, поэтому, если вы хотите узнать, является ли скаляр одновременно определенным и не длина 0, вам нужна только одна логическая проверка: if (length $x). 0 и undef оба являются ложными результатами. Обратите внимание, что до Perl 5.12 это вызывало предупреждение, так как length undef пытался использовать undef в качестве строки, как это делает eq.

person Grinnz    schedule 06.02.2020
comment
Гриннз, спасибо за разъяснения. Теперь я понимаю свои основные путаницы: 1) между eq и ==; 2) между определенным и undef. Я также заметил, что eq и == взаимозаменяемы между строкой и числом, за исключением undef. Еще один момент: undef $x или $x = undef работают как для строковых, так и для числовых значений при присвоении (очистке) значений, но работают только для числового сравнения. Любые исправления/комментарии по моим наблюдениям? - person Douglas; 07.02.2020
comment
@Douglas Извините, я не очень понимаю, что вы пытаетесь сказать. eq — всегда сравнение строк, == — всегда числовое сравнение, есть значения, которые представляют собой разные строки, но одно и то же число, и наоборот. undef не имеет ничего общего со сравнениями любого типа и эквивалентен пустой строке по строке и равен 0 по числовому значению. - person Grinnz; 07.02.2020
comment
Еще раз спасибо. Теперь я понимаю проблему. Мой последний комментарий не имеет особого смысла, так как я неправильно использовал == и undef (хотя это частично сработало). - person Douglas; 07.02.2020