Я только начал работу с новой командой нового места. Они сказали мне, что мы возвращаем ref вместо ценности в наших perl-модулях. Также я увидел что-то вроде return +{foo=>'bar'}; and return {foo=>'bar'};
В чем разница? И нужно ли возвращать ref или значение?Разница между возвратом + {} или {} в perl от функции и возвратом ref или значением
ответ
+
совершенно бесполезен.
Во-первых, некоторый фон.
Язык Perl имеет двусмысленности. Возьмем, к примеру
sub f {
{ } # Is this a hash constructor or a block?
}
{ }
действует синтаксис для блока («голое петля»).
{ }
является допустимым синтаксисом для хэш-конструктора.
И оба разрешены как заявление!
Поэтому Perl должен угадать. Perl обычно догадывается правильно, но не всегда. Вы можете дать ему «подсказки». Unary-+
можно использовать для этого. Unary-+
- полностью прозрачный оператор; он ничего не делает. Однако за ним должно следовать выражение (а не утверждение). { }
имеет только одно возможное значение как выражение.
Аналогичным образом вы можете обмануть Perl, чтобы угадать в другую сторону.
{; } # Perl looks head, and sees that this must be a block.
Вот пример, в котором Perl угадает неверно:
map { {} } 1..5 # ok. Creates 5 hashes and returns references to them.
map {}, 1..5 # XXX Perl guesses you were using "map BLOCK LIST".
map +{}, 1..5 # ok. Perl parses this as "map EXPR, LIST".
Что касается кода в вопросе, return
должно сопровождаться выражением (если что-нибудь), так что есть только один возможный интерпретация для return { ... };
, поэтому +
здесь совершенно бесполезен.
Большинство людей только устраняют необходимость при необходимости. Другие могут добавить +
всякий раз, когда это неоднозначно (даже если Perl догадается правильно). Но это он в первый раз, когда я слышал об использовании +
перед каждым конструктором хэшей.
Очень приятное объяснение, которое устраняет двусмысленность от двусмысленности. – stevieb
Обратите внимание, что поскольку 'map {}, 1..5;' имеет только одну действительную интерпретацию, поэтому Perl мог бы понять, что вы имели в виду, а не гадать. 1) Предполагается, что никто не делает никаких синтаксических ошибок, и 2) Когда вы устраняете двусмысленность, вы не только устраняете ошибку для Perl, но и для читателя. Короче говоря, лучше всего знать значение токенов как можно скорее. – ikegami
В чем разница?
Все те же, что и +
посторонние. Вы можете увидеть это с помощью B::Deparse:
$ perl -MO=Deparse -e'sub foo { return { foo => "bar" } }'
sub foo {
return {'foo', 'bar'};
}
-e syntax OK
$ perl -MO=Deparse -e'sub foo { return +{ foo => "bar" } }'
sub foo {
return {'foo', 'bar'};
}
-e syntax OK
В обеих случаях вы возвращаете ссылку на хэш.
Как Хантер Макмиллена сказал в комментариях, есть некоторые случаи, когда вам нужно использовать унарный оператор +
для разрешения неоднозначности.
Например, чтобы различать анонимный хэш и блок в map
:
$ perl -e'@a = map { $_ => "foo" }, 1..3' # { ... } treated as a block
syntax error at -e line 1, near "},"
Execution of -e aborted due to compilation errors.
$ perl -e'@a = map +{ $_ => "foo" }, 1..3' # { ... } treated as a hashref
И нужно ли возвращать реф или значение?
К «возвращает значение,» Я предполагаю, что ваши коллеги означают что-то вроде этого:
sub foo {
my %bar = (baz => 'qux');
return %bar; # as opposed to \%bar
}
my %hash = foo();
Подпрограммы могут только возвращать список скаляров, так что это примерно эквивалентно
my %hash = ('baz', 'qux');
Если %bar
содержит много элементов, копирование этого списка становится дорогим, поэтому лучше вернуть ссылку:
sub foo {
my %bar = (baz => 'qux');
return \%bar;
}
my $hashref = foo();
Примечание: Deparse является хорошей ссылкой, но это не является окончательным. Если вы хотите получить окончательное сравнение, вы можете использовать 'diff -u <(perl -MO = Concise, -exec, foo -e'sub foo {return {foo =>" bar "}} '2> & 1) <(perl -MO = Concise, -exec, foo -e'sub foo {return + {foo => "bar"}} '2> & 1) '. – ikegami
Используется иногда для устранения неоднозначности между ссылкой HASH и выражением BLOCK. Вы можете прочитать больше об этом в разделе '' perldoc perlref' '(http://perldoc.perl.org/perlref.html) –
О, дорогой. Perl, написанные программистами, не являющимися Perl! Неужели вам не нужно писать 'return \ 1'? Но всегда возвращать хеширование или массивные ссылки - это рецепт утечек памяти. – Borodin
«return ref вместо ценности» ... Я это видел. Обычно это означает, что возвращаемое значение всегда будет * ссылкой (будь то хэш, массив и т. Д.), Даже если оно пустое. Поэтому, если все хорошо, вы можете получить заполненную хеш-ссылку, но при неудаче или успехе, но ничего не сделано, пустой ref '{}' (хэш-код в этом случае). Затем вызывающий может: 'if (! Exists $ return -> {expected}) {do_something(); ...} ' – stevieb