Как вы разыменовываете возвращаемые значения? - PullRequest
2 голосов
/ 13 октября 2011

У меня постоянно возникают проблемы с разыменованием, особенно при возврате значений из функций.

Похоже, проблема в том, что всякий раз, когда вы возвращаете что-либо, кроме скаляра, вы на самом деле возвращаете этот объект по ссылке - это хорошо для меня - но говорите, когда мы передаем эти ссылки другим функциям, и нам нужен доступ ких кишки снова, как мы делаем это правильно?

Я продолжаю сталкиваться с ошибками вроде: "ожидание, что четное число параметров получило ссылку" или что-то в этом роде.

Есть ли общее правило, которое я могу использовать, чтобы упростить весь этот процесс? Я бы почти хотел, чтобы мне не пришлось беспокоиться о разыменовании!

Вот примерчто-то, что я пытался сделать ранее сегодня, и столкнулось со всевозможными проблемами разыменования, которые я потратил пару часов, пытаясь прорваться через мой путь - так что после прочтения, попытки и неудачи я здесь, чтобы попросить вас о сбое.

Объект Person

Person
 has name [Str]
 has madeby [Str]
 has height [Num]
 has id [Num]

Различные способы создания объекта Person

sub person_maker{
 my($this,%options) = @_;
 my $person = Person->new(%options);
   return $person;
}

sub make_person_named_james{
 my($this,$options) = @_;
 my $default = { name => 'James', madeby => 'name' };
   $options = ($options,$defaults); #merge default and options hash
   return($this->person_maker($options));
}

sub make_person_from_id{
 my($this,$id) = @_;
 my $default = { name => 'nameless person', madeby => 'id' };
   $default = ($default,{ id => $id });
   return($this->person_maker($default);
}

sub make_person_from_person{
 my($this,$person) = @_;
 my $person_options = {
   name => $person->name().'_twin',
   height => $person->height(),
   id => $person->id() + 1,
   madeby => 'person'
 };
 return($this->person_make($person_options));
}
  • Возврат функции hash object => фактически возвращается как ссылка на хеш
  • Func возвращает ссылка на хеш => фактически возвращается как скаляр
  • Func возвращает массив object => фактически возвращает ссылку на массив
  • Func возвращает ссылку на массив => он на самом деле возвращает скаляр ?
  • Func возвращает скаляр => it фактически возвращает значение скаляра?

Поправьте меня, если я что-то понял в этом неправильно.

Тогда еще одна проблема для меня вточка потребления аргументов функции ..

В зависимости от того, что я верну, эти плохие парни будут вести себя по-разному!

    sub myfunc{
      my($self,$args) = @_ # list of arguments (what if the args are mixed?)
  OR
      my($self,$args) = $_ # scalar (this wont work here $args will by undef
  OR
      my $self = shift; # pop the first arg
      my $args = shift; # pop the second arg
  OR
      my $self = $_[0] 
      my $args = $_[1]

Плюс!Существует слишком много документов, многие из них устарели, поэтому трудно точно определить, что лучше или лучше всего делать в таких ситуациях.

Если у кого-то есть магическая карта, в которой прописано, когда использовать эти различные настройки и как разыменовывать данные в определенных сценариях, благословенные хэши, хэш-ссылки, скаляры и т. Д. И т. Д., Я был бы вечно благодарен, поскольку япотраченные впустую часы, пытаясь расшифровать это.

Ответы [ 2 ]

10 голосов
/ 13 октября 2011

Все ссылки являются скалярными значениями.

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

my $array_ref = [];
print ref $array_ref;  # prints: ARRAY

Разыменование различных типов

  • Скалярная ссылка: $$scalar_ref

  • Ссылка на массив: @$array_ref

  • Ссылка на хэш: %$hash_ref

@_

@_ содержит псевдонимы параметров.Изменение @_ приводит к изменению исходных значений.Всегда делайте копии параметров как можно скорее и работайте с этими копиями;которую вы можете безопасно изменить без изменения исходных значений.

Аргументы и возвращаемые значения

В Perl все аргументы вызова функции сведены (свернуты) в список (таким образом теряя свои идентичности) и т. д.возвращаемые значения.С точки зрения функции, она может принимать только список значений single и может возвращать только список значений single .

Примеры сценариев:

Скалярный аргумент функции:

sub foo {
    my $arg = shift;
}

То же самое относится ко всем ссылкам;ссылки являются скалярными значениями.

Аргумент массива для функции:

sub foo {
    my @args = @_;
}

foo( 'bar', 'baz' );
foo( ( 'bar', 'baz' ), ( 'qux', 'spam' ) );  # In no way can the foo subroutine identify that the original arguments were two lists (same with arrays).

Аргумент хеш-функции для функции:

sub foo {
    my %arg = @_;
}

foo( 'bar' => 'baz' );
foo( ( 'bar' => 'baz' ), ( 'qux' => 'spam' ) );  # In no way can the foo subroutine identify that the original arguments were two hashes.

Всегда передавать ссылки, когда несколько списков(массивы) или хэши.Таким образом, вы можете идентифицировать списки индивидуально.

$_ и @_ отличаются

Цитирование вашего кода (который использует $_ неправильно):

my($self,$args) = $_ # scalar (this wont work here $args will by undef

$_ называется переменной по умолчанию и используется в ряде случаев, когда явная переменная не указана.@_, с другой стороны, используется только для хранения параметров массива (псевдонимов) внутри функции.Чтобы ссылаться на каждый элемент, мы можем использовать: $_[0], $_[1], и так далее.

Ссылки

  • Подробнее о предопределенных переменных в Perl можно узнать изperldoc perlvar.Я всегда использую perldoc -v '$special_variable' из моего терминала.Если вы используете Windows, одинарные кавычки должны быть заменены на двойные: perldoc -v "$special_variable".

  • Подпрограммы Perl: perldoc perlsub

  • Perl-ссылки и вложенные структуры данных: perldoc perlref

4 голосов
/ 13 октября 2011

Вам не хватает некоторых важных аспектов работы со ссылками.

Начиная с основ, идентификатором в Perl является строка, соответствующая [a-zA-Z_]\w+, исключая сложности юникода.Этот идентификатор может быть пустым или иметь префикс с символом.

Наиболее важным и часто пропускаемым символом является глоб, *, который является контейнером всех переменных (по крайней мере, до тех пор, пока my не должен былиспортить вечеринку и быть другим, прячась в блокноте).

Если у вас есть идентификатор с именем foo, то шар *foo содержит все, что foo может быть:

$foo as a scalar, a singular value
@foo as an array, a plural value
%foo as a hash, a plural value
&foo as code, singular if a reference \&foo, could be plural if making a call

Существуют и другие типы, но они встречаются реже.

В каждом из приведенных выше примеров сигил помещается перед идентификатором и разыменовывает ссылочные значения, хранящиеся в глобе *foo.Полный синтаксис этого немного громоздкий @{*foo{ARRAY}}, поэтому perl позволяет вам опустить печально пропущенный символ glob и использовать другие напрямую.Вы можете оставить скобки, ${foo} или @{foo} или любой другой символ, что означает то же самое, что и $foo и @foo соответственно.

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

my $scalar_foo_ref = \$foo;

say $$scalar_foo_ref;   # prints $foo
say ${$scalar_foo_ref}; # same

Символ всегда ожидает разыменования aзначение его типа (или того, которое может притвориться), и в противном случае будет выдано сообщение об ошибке.

Итак, предположим следующий код:

my @array = qw(a b c);

say $array[0];  # a
say join ', ' => @array;  # a, b, c

Вы можете легко преобразовать его в использование ссылок.,Сначала вы измените объявление, чтобы использовать ссылки, которые являются скалярами и хранятся в $foo:

my $array = [qw(a b c)]; # square brackets make an array ref
# or
my $array = \@array_of_hopefully_another_name; # \ does too

А затем в остальной части кода подставьте строку array с именемссылка, $array:

say $$array[0];  # a
say join ', ' => @$array;  # a, b, c

Все, ссылки есть.Итак, наконец, к вашему коду.Возьмите следующие строки:

my $default = { name => 'James', madeby => 'name' };
$options = ($options,$defaults); #merge default and options hash

Во первых, вы правильно используете конструкцию {...} для создания анонимной ссылки на хеш.Вы могли бы также написать это в ужасно многословной форме как:

my $default = do {my %hash = (name => 'James', madeby => 'name'); \%hash};

Но не делайте этого.

Следующая строка - это то, где возникают проблемы, и где вам нужно следоватьправила подстановки сверху.Вы, наверное, видели код, который выглядит следующим образом:

%options = (%options, %defaults);

И когда вы сменили сигил, все пошло не так.Что на самом деле делает perl, когда видит:

$options = ($options, $defaults);

Выполняется ли он, а затем выбрасывает все, кроме последнего элемента списка (в данном случае ($options,, а затем назначает последний элемент скаляру наlhs из =, что делает вашу строку эквивалентной:

$options = $defaults;

Что, конечно, не то, что вы хотели. Вместо этого замените свои имена хеш-ссылок на имена без слов:

%$options = (%$options, %$defaults);

Возможно, это слияние в неправильном порядке, при этом ваши значения по умолчанию переопределяют параметры. Чтобы исправить это, просто поменяйте местами:

%$options = (%$defaults, %$options);

Примените эти изменения в коде, где вы используете ссылки.Вещи должны снова обрести смысл.

...