Как вы разыменовываете возвращаемые значения?

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

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

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

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

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

Объект-человек

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));
}
  • Func возвращает объект хэш => фактически возвращает как ссылку на хэш.
  • Func возвращает ссылку на хэш => фактически возвращает как скаляр.
  • Func возвращает объект массив => фактически возвращает ссылку на массив
  • Func возвращает ссылку на массив => на самом деле возвращает скаляр?
  • Func возвращает скаляр => он действительно возвращает значение скаляра?

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

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

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

    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]

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

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


person qodeninja    schedule 13.10.2011    source источник


Ответы (2)


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

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

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

Удаление ссылок на разные типы

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

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

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

@_

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

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

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

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

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

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

person Alan Haggai Alavi    schedule 13.10.2011
comment
я отклонил принятый ответ, потому что он не отвечает напрямую на заданный вопрос. OP хочет разыменовать возвращаемое значение функции. однако принятый ответ говорит об аргументах функции. полная противоположность возвращаемого значения! возможно, в конце ответа вы найдете ответ на этот вопрос, но этот ответ определенно не соответствует действительности. ОП четко знает, что такое ссылка и как ее использовать. но даже я спустя годы так и не нашел пути к моему @rv = @$functionName_asRef($param1, $param2); - person Jarett Lloyd; 27.10.2018

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

Начиная с основ, идентификатор в 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

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

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

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,, а затем присваивает последний элемент скаляру в левой части =, делая вашу строку эквивалентной:

$options = $defaults;

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

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

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

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

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

person Eric Strom    schedule 13.10.2011