Передача скалярной ссылки в Perl - PullRequest
6 голосов
/ 03 мая 2011

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

#!/usr/bin/perl
$i = 2;
subr(\$i);
sub subr{
    print $_[0]."\n";
    print $$_[0]."\n";
}

Я думал, что первая строка будет печататьадрес и вторая строка вернут номер, но вторая пустая строка.Кто-то еще указал мне на это: ${$_[0]}, и он напечатает номер.Но она не знала причину, почему без {} она не работает и почему она работает с {}.Так что же случилось?

Ответы [ 4 ]

14 голосов
/ 03 мая 2011

Это потому, что ваш второй оператор печати эквивалентен этому ...

my $x = $$_; print $x[0];

Когда вы хотите получить

my $x = $_[0]; print $$x;

Другими словами, разыменование происходит до того, какиндекс массива вычисляется.

Когда вы добавляете эти curl-wurlies, он говорит perl, как интерпретировать выражение так, как вы хотите;сначала он оценит $_[0], а затем отменит ссылку, чтобы получить значение.

8 голосов
/ 03 мая 2011

Это порядок оценки.

  $$_[0] is evaluated as {$$_}[0]

Это 0-й элемент ссылки на скалярную переменную $ _. Сначала он берет ссылку, а затем пытается найти ее 0-й элемент.

  ${$_[0]}

Это ссылка на 0-й элемент массива @_. Сначала он находит 0-й элемент, а затем получает ссылку на него.

Если вы установите use strict и use warnings в верхней части кода, вы увидите множество предупреждений о неопределенных значениях с первой попытки.

3 голосов
/ 03 мая 2011

$$_[0] похоже на $foo[0], только с $ _ вместо имени массива.Это означает, что $ _ рассматривается как ссылка на массив, а выражение вообще не включает скалярную ссылку $_[0].$_->[0] эквивалентно, используя альтернативный синтаксис ->.Синтаксис разыменования может показаться произвольным и трудным для запоминания, но в нем есть смысл и порядок;очень хорошая презентация в http://perlmonks.org/?node=References+quick+reference.

1 голос
/ 03 мая 2011

Вам не нужно передавать ссылку на $i.Обозначение $_[0] является псевдонимом для $i, когда вы вызываете его как subr( $i ).

use strict;
use warnings;
use Test::More tests => 2;

sub subr{ $_[0]++ } # messing with exactly what was passed first
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

Другой пример:

use strict;
use warnings;
use Test::More tests => 6;
use Test::Exception;

sub subr{ $_[0]++ }
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );

sub subr2 { $_[0] .= 'x'; }
dies_ok { subr2( 'lit' ); } 'subr2 *dies* trying to modify a literal';
lives_ok { 
    my $s = 'lit';
    subr2( $s );
    is( $s, 'litx', q[$s eq 'litx'] );
    subr2(( my $s2 = 'lit' ));
    is( $s2, 'litx', q[$s2 eq 'litx'] );
} 'subr2 lives with heap variables';

Выход:

ok 1 - $i == 2
ok 2 - $i == 3
ok 3 - subr2 *dies* trying to modify a literal
ok 4 - $s eq 'litx'
ok 5 - $s2 eq 'litx'
ok 6 - subr2 lives with heap variables
1..6
...