2017-02-07 2 views
3

Я только начал работу с новой командой нового места. Они сказали мне, что мы возвращаем ref вместо ценности в наших perl-модулях. Также я увидел что-то вроде return +{foo=>'bar'}; and return {foo=>'bar'}; В чем разница? И нужно ли возвращать ref или значение?Разница между возвратом + {} или {} в perl от функции и возвратом ref или значением

+4

Используется иногда для устранения неоднозначности между ссылкой HASH и выражением BLOCK. Вы можете прочитать больше об этом в разделе '' perldoc perlref' '(http://perldoc.perl.org/perlref.html) –

+3

О, дорогой. Perl, написанные программистами, не являющимися Perl! Неужели вам не нужно писать 'return \ 1'? Но всегда возвращать хеширование или массивные ссылки - это рецепт утечек памяти. – Borodin

+0

«return ref вместо ценности» ... Я это видел. Обычно это означает, что возвращаемое значение всегда будет * ссылкой (будь то хэш, массив и т. Д.), Даже если оно пустое. Поэтому, если все хорошо, вы можете получить заполненную хеш-ссылку, но при неудаче или успехе, но ничего не сделано, пустой ref '{}' (хэш-код в этом случае). Затем вызывающий может: 'if (! Exists $ return -> {expected}) {do_something(); ...} ' – stevieb

ответ

10

+ совершенно бесполезен.


Во-первых, некоторый фон.

Язык 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 догадается правильно). Но это он в первый раз, когда я слышал об использовании + перед каждым конструктором хэшей.

+1

Очень приятное объяснение, которое устраняет двусмысленность от двусмысленности. – stevieb

+0

Обратите внимание, что поскольку 'map {}, 1..5;' имеет только одну действительную интерпретацию, поэтому Perl мог бы понять, что вы имели в виду, а не гадать. 1) Предполагается, что никто не делает никаких синтаксических ошибок, и 2) Когда вы устраняете двусмысленность, вы не только устраняете ошибку для Perl, но и для читателя. Короче говоря, лучше всего знать значение токенов как можно скорее. – ikegami

9

В чем разница?

Все те же, что и + посторонние. Вы можете увидеть это с помощью 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(); 
+2

Примечание: 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

Смежные вопросы