Передача скалярной ссылки в Perl

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

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

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


person user685275    schedule 03.05.2011    source источник


Ответы (4)


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

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

Когда то, что вы хотите,

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

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

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

person Ed Guiness    schedule 03.05.2011

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

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

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

  ${$_[0]}

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

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

person bot403    schedule 03.05.2011

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

person ysth    schedule 03.05.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
person Axeman    schedule 03.05.2011